]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Wed, 5 Mar 2003 18:00:03 +0000 (18:00 +0000)
committernobody <>
Wed, 5 Mar 2003 18:00:03 +0000 (18:00 +0000)
'carlton_dictionary-branch'.

Cherrypick from master 2003-03-05 18:00:02 UTC Daniel Jacobowitz <drow@false.org> ' * dwarf2expr.c (new_dwarf_expr_context): Add (void) to definition.':
    bfd/doc/fdl.texi
    bfd/elf32-ppc.h
    gdb/coff-pe-read.c
    gdb/coff-pe-read.h
    gdb/dwarf2expr.c
    gdb/dwarf2expr.h
    gdb/dwarf2loc.c
    gdb/dwarf2loc.h
    gdb/observer.c
    gdb/observer.h
    gdb/tui/tui-interp.c
    libiberty/acconfig.h
    libiberty/lrealpath.c
    libiberty/physmem.c

14 files changed:
bfd/doc/fdl.texi [new file with mode: 0644]
bfd/elf32-ppc.h [new file with mode: 0644]
gdb/coff-pe-read.c [new file with mode: 0644]
gdb/coff-pe-read.h [new file with mode: 0644]
gdb/dwarf2expr.c [new file with mode: 0644]
gdb/dwarf2expr.h [new file with mode: 0644]
gdb/dwarf2loc.c [new file with mode: 0644]
gdb/dwarf2loc.h [new file with mode: 0644]
gdb/observer.c [new file with mode: 0644]
gdb/observer.h [new file with mode: 0644]
gdb/tui/tui-interp.c [new file with mode: 0644]
libiberty/acconfig.h [new file with mode: 0644]
libiberty/lrealpath.c [new file with mode: 0644]
libiberty/physmem.c [new file with mode: 0644]

diff --git a/bfd/doc/fdl.texi b/bfd/doc/fdl.texi
new file mode 100644 (file)
index 0000000..176233c
--- /dev/null
@@ -0,0 +1,366 @@
+@c -*-texinfo-*-
+@appendix GNU Free Documentation License
+@center Version 1.1, March 2000
+
+@display
+Copyright (C) 2000, 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
+@sp 1
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+written 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.
+
+@sp 1
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work that contains a
+notice placed by the copyright holder saying it can be distributed
+under the terms of this License.  The ``Document'', below, refers to any
+such manual or work.  Any member of the public is a licensee, and is
+addressed as ``you.''
+
+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.  (For example, 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.
+
+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 ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, whose contents can be viewed and edited directly and
+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 has been designed to thwart or discourage
+subsequent modification by readers is not Transparent.  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 designed for human modification.  Opaque formats include
+PostScript, PDF, 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 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.
+@sp 1
+@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.
+@sp 1
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies 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 publicly-accessible computer-network location containing a complete
+Transparent copy of the Document, free of added material, which the
+general network-using public has access to download anonymously at no
+charge using public-standard network protocols.  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.
+@sp 1
+@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:
+
+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 less than five).@*
+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'', and 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. In any section entitled ``Acknowledgements'' or ``Dedications'',
+   preserve the section's title, 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 as ``Endorsements''
+   or to conflict in title with any Invariant Section.@*
+@sp 1
+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.
+@sp 1
+@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.
+
+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.''
+@sp 1
+@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.
+@sp 1
+@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, does not as a whole count as a Modified Version
+of the Document, provided no compilation copyright is claimed for the
+compilation.  Such a compilation is called an ``aggregate'', and this
+License does not apply to the other self-contained works thus compiled
+with the Document, on account of their being thus compiled, if they
+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 quarter
+of the entire aggregate, the Document's Cover Texts may be placed on
+covers that surround only the Document within the aggregate.
+Otherwise they must appear on covers around the whole aggregate.
+@sp 1
+@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 provided that you also include the
+original English version of this License.  In case of a disagreement
+between the translation and the original English version of this
+License, the original English version will prevail.
+@sp 1
+@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.
+@sp 1
+@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
+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
+
+@unnumberedsec 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.1
+or any later version published by the Free Software Foundation;
+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}.
+A copy of the license is included in the section entitled "GNU
+Free Documentation License."
+@end group
+@end smallexample
+
+If you have no Invariant Sections, write ``with no Invariant Sections''
+instead of saying which ones are invariant.  If you have no
+Front-Cover Texts, write ``no Front-Cover Texts'' instead of
+``Front-Cover Texts being @var{list}''; likewise for Back-Cover Texts.
+
+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.
diff --git a/bfd/elf32-ppc.h b/bfd/elf32-ppc.h
new file mode 100644 (file)
index 0000000..ead9c94
--- /dev/null
@@ -0,0 +1,23 @@
+/* PowerPC-specific support for 64-bit ELF.
+   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.  */
+
+bfd_boolean ppc_elf_tls_setup
+  PARAMS ((bfd *, struct bfd_link_info *));
+bfd_boolean ppc_elf_tls_optimize
+  PARAMS ((bfd *, struct bfd_link_info *));
diff --git a/gdb/coff-pe-read.c b/gdb/coff-pe-read.c
new file mode 100644 (file)
index 0000000..2d1e854
--- /dev/null
@@ -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
+\f
+/* 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;
+    }
+}
+\f
+/* 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;
+       }
+    }
+}
+\f
+/* 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);
+}
+\f
+/* 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/gdb/coff-pe-read.h b/gdb/coff-pe-read.h
new file mode 100644 (file)
index 0000000..c5d4e68
--- /dev/null
@@ -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/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
new file mode 100644 (file)
index 0000000..7456979
--- /dev/null
@@ -0,0 +1,687 @@
+/* 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 = 10;
+  retval->stack = xmalloc (10 * 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 templen = ctx->stack_len * 2;
+      while (templen < (ctx->stack_len + need))
+          templen *= 2;
+      ctx->stack = xrealloc (ctx->stack,
+                            templen * sizeof (CORE_ADDR));
+      ctx->stack_allocated = templen;
+    }
+}
+
+/* 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.  */
+
+static CORE_ADDR
+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 ("read_address: Corrupted DWARF expression.");
+
+  *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+  result = extract_address (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");
+    }
+}
+\f
+/* 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)
+{
+  while (op_ptr < op_end)
+    {
+      enum dwarf_location_atom op = *op_ptr++;
+      CORE_ADDR result, memaddr;
+      ULONGEST uoffset, reg;
+      LONGEST offset;
+      int bytes_read;
+      enum lval_type expr_lval;
+
+      ctx->in_reg = 0;
+
+      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 = 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:
+         /* NOTE: in the presence of DW_OP_piece this check is incorrect.  */
+         if (op_ptr != op_end)
+           error ("DWARF-2 expression error: DW_OP_reg operations must be "
+                  "used alone.");
+
+         /* FIXME drow/2003-02-21: This call to read_reg could be pushed
+            into the evaluator's caller by changing the semantics for in_reg.
+            Then we wouldn't need to return an lval_type and a memaddr.  */
+         result = (ctx->read_reg) (ctx->baton, op - DW_OP_reg0, &expr_lval,
+                                   &memaddr);
+
+         if (expr_lval == lval_register)
+           {
+             ctx->regnum = op - DW_OP_reg0;
+             ctx->in_reg = 1;
+           }
+         else
+           result = memaddr;
+
+         break;
+
+       case DW_OP_regx:
+         op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+         if (op_ptr != op_end)
+           error ("DWARF-2 expression error: DW_OP_reg operations must be "
+                  "used alone.");
+
+         result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr);
+
+         if (expr_lval == lval_register)
+           {
+             ctx->regnum = reg;
+             ctx->in_reg = 1;
+           }
+         else
+           result = memaddr;
+
+         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,
+                                     &expr_lval, &memaddr);
+           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, &expr_lval, &memaddr);
+           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;
+           (ctx->get_frame_base) (ctx->baton, &datastart, &datalen);
+           dwarf_expr_eval (ctx, datastart, datalen);
+           result = dwarf_expr_fetch (ctx, 0);
+           if (! ctx->in_reg)
+             {
+               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 = read_address (buf,
+                                      buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
+                                      &bytes_read);
+             }
+           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 = 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 = 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, 1);
+           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:
+         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");
+       }
+
+      /* Most things push a result value.  */
+      dwarf_expr_push (ctx, result);
+    no_push:;
+    }
+}
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
new file mode 100644 (file)
index 0000000..3d0fcb3
--- /dev/null
@@ -0,0 +1,103 @@
+/* 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.  LVALP will be set
+     to the kind of lval this register is (generally lval_register
+     for the current frame's registers or lval_memory for a register
+     saved to the stack).  For lval_memory ADDRP will be set to the
+     saved location of the register.  */
+  CORE_ADDR (*read_reg) (void *baton, int regnum, enum lval_type *lvalp,
+                        CORE_ADDR *addrp);
+
+  /* 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 in REGNUM, and the result will be the contents of the
+     register.  */
+  int in_reg;
+
+  /* If the result is in a register, the register number.  */
+  int regnum;
+};
+
+struct dwarf_expr_context *new_dwarf_expr_context ();
+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);
+
+#endif
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
new file mode 100644 (file)
index 0000000..9ea9941
--- /dev/null
@@ -0,0 +1,356 @@
+/* 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 "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
+
+/* 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, enum lval_type *lvalp,
+                    CORE_ADDR *addrp)
+{
+  struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+  CORE_ADDR result;
+  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, lvalp, addrp, &realnum,
+                 buf);
+  result = extract_address (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)
+{
+  struct symbol *framefunc;
+  struct dwarf2_locexpr_baton *symbaton;
+  struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+  framefunc = get_frame_function (debaton->frame);
+  symbaton = SYMBOL_LOCATION_BATON (framefunc);
+  *start = symbaton->data;
+  *length = symbaton->size;
+}
+
+/* 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);
+  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;
+
+  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);
+
+  retval = allocate_value (SYMBOL_TYPE (var));
+  VALUE_BFD_SECTION (retval) = SYMBOL_BFD_SECTION (var);
+
+  if (ctx->in_reg)
+    {
+      store_unsigned_integer (VALUE_CONTENTS_RAW (retval),
+                             TYPE_LENGTH (SYMBOL_TYPE (var)),
+                             dwarf_expr_fetch (ctx, 0));
+      VALUE_LVAL (retval) = lval_register;
+      VALUE_REGNO (retval) = ctx->regnum;
+    }
+  else
+    {
+      result = dwarf_expr_fetch (ctx, 0);
+      VALUE_LVAL (retval) = lval_memory;
+      VALUE_LAZY (retval) = 1;
+      VALUE_ADDRESS (retval) = result;
+    }
+
+  free_dwarf_expr_context (ctx);
+
+  return retval;
+}
+
+
+
+
+\f
+/* 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, enum lval_type *lvalp,
+                           CORE_ADDR *addrp)
+{
+  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;
+
+  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);
+
+  free_dwarf_expr_context (ctx);
+
+  return baton.needs_frame;
+}
+
+
+
+\f
+/* 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;
+    }
+
+  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.  */
+
+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);
+
+  if (dlbaton->size == 0)
+    error ("Symbol \"%s\" has been optimized out.",
+          SYMBOL_PRINT_NAME (symbol));
+
+  if (dlbaton->size == 1
+      && dlbaton->data[0] >= DW_OP_reg0
+      && dlbaton->data[0] <= DW_OP_reg31)
+    {
+      value->kind = axs_lvalue_register;
+      value->u.reg = dlbaton->data[0] - DW_OP_reg0;
+    }
+  else if (dlbaton->data[0] == DW_OP_regx)
+    {
+      ULONGEST reg;
+      read_uleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
+                   &reg);
+      value->kind = axs_lvalue_register;
+      value->u.reg = reg;
+    }
+  else if (dlbaton->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 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
+                             &frame_offset);
+      if (buf_end != dlbaton->data + dlbaton->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));
+}
+
+/* The set of location functions used with the DWARF-2 expression
+   evaluator.  */
+struct location_funcs dwarf2_locexpr_funcs = {
+  locexpr_read_variable,
+  locexpr_read_needs_frame,
+  locexpr_describe_location,
+  locexpr_tracepoint_var_ref
+};
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
new file mode 100644 (file)
index 0000000..fde1329
--- /dev/null
@@ -0,0 +1,39 @@
+/* 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
+
+/* This header is private to the DWARF-2 reader.  It is shared between
+   dwarf2read.c and dwarf2loc.c.  */
+
+/* The symbol location baton type used by the DWARF-2 reader (i.e.
+   SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  */
+
+struct dwarf2_locexpr_baton
+{
+  unsigned char *data;
+  unsigned short size;
+  struct objfile *objfile;
+};
+
+extern struct location_funcs dwarf2_locexpr_funcs;
+
+#endif
diff --git a/gdb/observer.c b/gdb/observer.c
new file mode 100644 (file)
index 0000000..92ec48e
--- /dev/null
@@ -0,0 +1,192 @@
+/* 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);
+}
diff --git a/gdb/observer.h b/gdb/observer.h
new file mode 100644 (file)
index 0000000..8b9a6db
--- /dev/null
@@ -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/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
new file mode 100644 (file)
index 0000000..f935ea4
--- /dev/null
@@ -0,0 +1,180 @@
+/* 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 "tui/tuiData.h"
+#include "readline/readline.h"
+#include "tui/tuiWin.h"
+#include "tui/tui.h"
+#include "tui/tuiIO.h"
+
+/* 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);
+
+  initializeStaticData ();
+
+  tui_initialize_io ();
+  tui_initialize_readline ();
+
+  return NULL;
+}
+
+static int
+tui_resume (void *data)
+{
+  gdb_setup_readline ();
+  tui_enable ();
+  return 1;
+}
+
+static int
+tui_suspend (void *data)
+{
+  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));
+}
diff --git a/libiberty/acconfig.h b/libiberty/acconfig.h
new file mode 100644 (file)
index 0000000..364cb41
--- /dev/null
@@ -0,0 +1,3 @@
+/* Define to `unsigned long' if <sys/types.h> doesn't define.  */
+#undef uintptr_t
+
diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c
new file mode 100644 (file)
index 0000000..b001b38
--- /dev/null
@@ -0,0 +1,128 @@
+/* Libiberty realpath.  Like realpath, but more consistent behavior.
+   Based on gdb_realpath from GDB.
+
+   Copyright 2003 Free Software Foundation, Inc.
+
+   This file is part of the libiberty 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.  */
+
+/*
+
+@deftypefn Replacement {const char*} lrealpath (const char *@var{name})
+
+Given a pointer to a string containing a pathname, returns a canonical
+version of the filename.  Symlinks will be resolved, and ``.'' and ``..''
+components will be simplified.  The returned value will be allocated using
+@code{malloc}, or @code{NULL} will be returned on a memory allocation error.
+
+@end deftypefn
+
+*/
+
+#include "config.h"
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+/* On GNU libc systems the declaration is only visible with _GNU_SOURCE.  */
+#if defined(HAVE_CANONICALIZE_FILE_NAME) \
+    && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
+extern char *canonicalize_file_name (const char *);
+#endif
+
+#if defined(HAVE_REALPATH)
+# if defined (PATH_MAX)
+#  define REALPATH_LIMIT PATH_MAX
+# else
+#  if defined (MAXPATHLEN)
+#   define REALPATH_LIMIT MAXPATHLEN
+#  endif
+# endif
+#endif
+
+char *
+lrealpath (filename)
+     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(REALPATH_LIMIT)
+  {
+    char buf[REALPATH_LIMIT];
+    const char *rp = realpath (filename, buf);
+    if (rp == NULL)
+      rp = filename;
+    return strdup (rp);
+  }
+#endif /* REALPATH_LIMIT */
+
+  /* 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 strdup (filename);
+    else
+      return rp;
+  }
+#endif
+
+  /* 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)
+  {
+    /* Find out the max path size.  */
+    long path_max = pathconf ("/", _PC_PATH_MAX);
+    if (path_max > 0)
+      {
+       /* PATH_MAX is bounded.  */
+       char *buf, *rp, *ret;
+       buf = malloc (path_max);
+       if (buf == NULL)
+         return NULL;
+       rp = realpath (filename, buf);
+       ret = strdup (rp ? rp : filename);
+       free (buf);
+       return ret;
+      }
+  }
+#endif
+
+  /* This system is a lost cause, just duplicate the filename.  */
+  return strdup (filename);
+}
diff --git a/libiberty/physmem.c b/libiberty/physmem.c
new file mode 100644 (file)
index 0000000..9185c12
--- /dev/null
@@ -0,0 +1,305 @@
+/* Calculate the size of physical memory.
+   Copyright 2000, 2001, 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 Paul Eggert.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_SYS_PSTAT_H
+# include <sys/pstat.h>
+#endif
+
+#if HAVE_SYS_SYSMP_H
+# include <sys/sysmp.h>
+#endif
+
+#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H
+# include <sys/sysinfo.h>
+# include <machine/hal_sysinfo.h>
+#endif
+
+#if HAVE_SYS_TABLE_H
+# include <sys/table.h>
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif
+
+#if HAVE_SYS_SYSTEMCFG_H
+# include <sys/systemcfg.h>
+#endif
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+/*  MEMORYSTATUSEX is missing from older windows headers, so define
+    a local replacement.  */
+typedef struct
+{
+  DWORD dwLength;
+  DWORD dwMemoryLoad;
+  DWORDLONG ullTotalPhys;
+  DWORDLONG ullAvailPhys;
+  DWORDLONG ullTotalPageFile;
+  DWORDLONG ullAvailPageFile;
+  DWORDLONG ullTotalVirtual;
+  DWORDLONG ullAvailVirtual;
+  DWORDLONG ullAvailExtendedVirtual;
+} lMEMORYSTATUSEX;
+typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
+#endif
+
+#include "libiberty.h"
+
+/* Return the total amount of physical memory.  */
+double
+physmem_total ()
+{
+#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
+  { /* This works on linux-gnu, solaris2 and cygwin.  */
+    double pages = sysconf (_SC_PHYS_PAGES);
+    double pagesize = sysconf (_SC_PAGESIZE);
+    if (0 <= pages && 0 <= pagesize)
+      return pages * pagesize;
+  }
+#endif
+
+#if HAVE_PSTAT_GETSTATIC
+  { /* This works on hpux11.  */
+    struct pst_static pss;
+    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0))
+      {
+       double pages = pss.physical_memory;
+       double pagesize = pss.page_size;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
+  { /* This works on irix6. */
+    struct rminfo realmem;
+    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
+      {
+       double pagesize = sysconf (_SC_PAGESIZE);
+       double pages = realmem.physmem;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_GETSYSINFO && defined GSI_PHYSMEM
+  { /* This works on Tru64 UNIX V4/5.  */
+    int physmem;
+
+    if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem),
+                   NULL, NULL, NULL) == 1)
+      {
+       double kbytes = physmem;
+
+       if (0 <= kbytes)
+         return kbytes * 1024.0;
+      }
+  }
+#endif
+
+#if HAVE_SYSCTL && defined HW_PHYSMEM
+  { /* This works on *bsd and darwin.  */
+    unsigned int physmem;
+    size_t len = sizeof physmem;
+    static int mib[2] = { CTL_HW, HW_PHYSMEM };
+
+    if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0
+       && len == sizeof (physmem))
+      return (double) physmem;
+  }
+#endif
+
+#if HAVE__SYSTEM_CONFIGURATION
+  /* This works on AIX.  */
+  return _system_configuration.physmem;
+#endif
+
+#if defined _WIN32
+  { /* this works on windows */
+    PFN_MS_EX pfnex;
+    HMODULE h = GetModuleHandle ("kernel32.dll");
+
+    if (!h)
+      return 0.0;
+
+    /*  Use GlobalMemoryStatusEx if available.  */
+    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
+      {
+       lMEMORYSTATUSEX lms_ex;
+       lms_ex.dwLength = sizeof lms_ex;
+       if (!pfnex (&lms_ex))
+         return 0.0;
+       return (double) lms_ex.ullTotalPhys;
+      }
+
+    /*  Fall back to GlobalMemoryStatus which is always available.
+        but returns wrong results for physical memory > 4GB.  */
+    else
+      {
+       MEMORYSTATUS ms;
+       GlobalMemoryStatus (&ms);
+       return (double) ms.dwTotalPhys;
+      }
+  }
+#endif
+
+  /* Return 0 if we can't determine the value.  */
+  return 0;
+}
+
+/* Return the amount of physical memory available.  */
+double
+physmem_available ()
+{
+#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
+  { /* This works on linux-gnu, solaris2 and cygwin.  */
+    double pages = sysconf (_SC_AVPHYS_PAGES);
+    double pagesize = sysconf (_SC_PAGESIZE);
+    if (0 <= pages && 0 <= pagesize)
+      return pages * pagesize;
+  }
+#endif
+
+#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC
+  { /* This works on hpux11.  */
+    struct pst_static pss;
+    struct pst_dynamic psd;
+    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)
+       && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0))
+      {
+       double pages = psd.psd_free;
+       double pagesize = pss.page_size;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
+  { /* This works on irix6. */
+    struct rminfo realmem;
+    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
+      {
+       double pagesize = sysconf (_SC_PAGESIZE);
+       double pages = realmem.availrmem;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_TABLE && defined TBL_VMSTATS
+  { /* This works on Tru64 UNIX V4/5.  */
+    struct tbl_vmstats vmstats;
+
+    if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1)
+      {
+       double pages = vmstats.free_count;
+       double pagesize = vmstats.pagesize;
+
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_SYSCTL && defined HW_USERMEM
+  { /* This works on *bsd and darwin.  */
+    unsigned int usermem;
+    size_t len = sizeof usermem;
+    static int mib[2] = { CTL_HW, HW_USERMEM };
+
+    if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0
+       && len == sizeof (usermem))
+      return (double) usermem;
+  }
+#endif
+
+#if defined _WIN32
+  { /* this works on windows */
+    PFN_MS_EX pfnex;
+    HMODULE h = GetModuleHandle ("kernel32.dll");
+
+    if (!h)
+      return 0.0;
+
+    /*  Use GlobalMemoryStatusEx if available.  */
+    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
+      {
+       lMEMORYSTATUSEX lms_ex;
+       lms_ex.dwLength = sizeof lms_ex;
+       if (!pfnex (&lms_ex))
+         return 0.0;
+       return (double) lms_ex.ullAvailPhys;
+      }
+
+    /*  Fall back to GlobalMemoryStatus which is always available.
+        but returns wrong results for physical memory > 4GB  */
+    else
+      {
+       MEMORYSTATUS ms;
+       GlobalMemoryStatus (&ms);
+       return (double) ms.dwAvailPhys;
+      }
+  }
+#endif
+
+  /* Guess 25% of physical memory.  */
+  return physmem_total () / 4;
+}
+
+
+#if DEBUG
+
+# include <stdio.h>
+# include <stdlib.h>
+
+int
+main ()
+{
+  printf ("%12.f %12.f\n", physmem_total (), physmem_available ());
+  exit (0);
+}
+
+#endif /* DEBUG */
+
+/*
+Local Variables:
+compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c"
+End:
+*/