mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
* Makefile.in (XMLFILES): New.
(COMMON_OBS): Add xml-builtin.o. (xml-builtin.c, stamp-xml): New rules. (xml-tdesc.o): Update. * features/feature_to_c.sh: New file. * xml-support.c (MAX_XINCLUDE_DEPTH): Define. (struct gdb_xml_parser): Add dtd_name and is_xinclude. (gdb_xml_start_element): Initialize scope after possibly reallocating scopes. Move cleanup later. Handle the XInclude description specially. (gdb_xml_end_element): Only parse the body if there is a current element. Call XML_DefaultCurrent if there is no element. (gdb_xml_fetch_external_entity, gdb_xml_use_dtd): New. (struct xinclude_parsing_data, xinclude_start_include) (xinclude_end_include, xml_xinclude_default) (xml_xinclude_start_doctype, xml_xinclude_end_doctype) (xml_xinclude_xml_decl, xml_xinclude_cleanup, xinclude_attributes) (xinclude_elements, xml_process_xincludes, fetch_xml_builtin): New. * xml-support.h (xml_fetch_another, xml_process_xincludes) (fetch_xml_builtin, xml_builtin, gdb_xml_use_dtd): New declarations. * xml-tdesc.c (tdesc_parse_xml): Add fetcher_baton argument. Expand XInclude directives. Use the compiled in DTD. (fetch_xml_from_file): Add baton argument. Treat it as a containing directory name. Do not warn here. (file_read_description_xml): Update call. Warn here instead. Pass a dirname as baton. (fetch_available_features_from_target): New. (target_read_description_xml): Use it. * features/gdb-target.dtd: Add copyright notice. Use xinclude.dtd to handle XInclude. * features/xinclude.dtd: New file. * gdb.xml/bad-include.xml, gdb.xml/inc-2.xml, gdb.xml/inc-body.xml, gdb.xml/includes.xml, gdb.xml/tdesc-xinclude.exp: New files. * gdb.texinfo (Target Description Format): Add section on XInclude.
This commit is contained in:
parent
7bd1c9613d
commit
108546a0ea
@ -1,3 +1,37 @@
|
||||
2007-02-07 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* Makefile.in (XMLFILES): New.
|
||||
(COMMON_OBS): Add xml-builtin.o.
|
||||
(xml-builtin.c, stamp-xml): New rules.
|
||||
(xml-tdesc.o): Update.
|
||||
* features/feature_to_c.sh: New file.
|
||||
* xml-support.c (MAX_XINCLUDE_DEPTH): Define.
|
||||
(struct gdb_xml_parser): Add dtd_name and is_xinclude.
|
||||
(gdb_xml_start_element): Initialize scope after possibly reallocating
|
||||
scopes. Move cleanup later. Handle the XInclude description
|
||||
specially.
|
||||
(gdb_xml_end_element): Only parse the body if there is a current element.
|
||||
Call XML_DefaultCurrent if there is no element.
|
||||
(gdb_xml_fetch_external_entity, gdb_xml_use_dtd): New.
|
||||
(struct xinclude_parsing_data, xinclude_start_include)
|
||||
(xinclude_end_include, xml_xinclude_default)
|
||||
(xml_xinclude_start_doctype, xml_xinclude_end_doctype)
|
||||
(xml_xinclude_xml_decl, xml_xinclude_cleanup, xinclude_attributes)
|
||||
(xinclude_elements, xml_process_xincludes, fetch_xml_builtin): New.
|
||||
* xml-support.h (xml_fetch_another, xml_process_xincludes)
|
||||
(fetch_xml_builtin, xml_builtin, gdb_xml_use_dtd): New declarations.
|
||||
* xml-tdesc.c (tdesc_parse_xml): Add fetcher_baton argument. Expand
|
||||
XInclude directives. Use the compiled in DTD.
|
||||
(fetch_xml_from_file): Add baton argument. Treat it as a containing
|
||||
directory name. Do not warn here.
|
||||
(file_read_description_xml): Update call. Warn here instead. Pass
|
||||
a dirname as baton.
|
||||
(fetch_available_features_from_target): New.
|
||||
(target_read_description_xml): Use it.
|
||||
* features/gdb-target.dtd: Add copyright notice. Use xinclude.dtd
|
||||
to handle XInclude.
|
||||
* features/xinclude.dtd: New file.
|
||||
|
||||
2007-02-05 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* linux-thread-db.c (check_for_thread_db): Return early if we have
|
||||
|
@ -400,6 +400,9 @@ LINTFLAGS= $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
|
||||
RUNTEST = runtest
|
||||
RUNTESTFLAGS=
|
||||
|
||||
# XML files to build in to GDB.
|
||||
XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd
|
||||
|
||||
# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
|
||||
# interface to the serial port. Hopefully if get ported to OS/2, VMS,
|
||||
# etc., then there will be (as part of the C library or perhaps as
|
||||
@ -972,7 +975,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||
tramp-frame.o \
|
||||
solib.o solib-null.o \
|
||||
prologue-value.o memory-map.o xml-support.o \
|
||||
target-descriptions.o target-memory.o xml-tdesc.o
|
||||
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o
|
||||
|
||||
TSOBS = inflow.o
|
||||
|
||||
@ -1681,6 +1684,19 @@ po/$(PACKAGE).pot: force
|
||||
.PRECIOUS: objc-exp.c
|
||||
.PRECIOUS: p-exp.c
|
||||
|
||||
# XML rules
|
||||
|
||||
xml-builtin.c: stamp-xml; @true
|
||||
stamp-xml: $(srcdir)/features/feature_to_c.sh Makefile $(XMLFILES)
|
||||
rm -f xml-builtin.tmp
|
||||
AWK="$(AWK)" \
|
||||
$(SHELL) $(srcdir)/features/feature_to_c.sh \
|
||||
xml-builtin.tmp $(XMLFILES)
|
||||
$(SHELL) $(srcdir)/../move-if-change xml-builtin.tmp xml-builtin.c
|
||||
echo stamp > stamp-xml
|
||||
|
||||
.PRECIOUS: xml-builtin.c
|
||||
|
||||
#
|
||||
# gdb/ dependencies
|
||||
#
|
||||
@ -2876,7 +2892,7 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \
|
||||
xcoffsolib.o: xcoffsolib.c $(defs_h) $(bfd_h) $(xcoffsolib_h) $(inferior_h) \
|
||||
$(gdbcmd_h) $(symfile_h) $(frame_h) $(gdb_regex_h)
|
||||
xml-tdesc.o: xml-tdesc.c $(defs_h) $(target_h) $(target_descriptions_h) \
|
||||
$(xml_tdesc_h) $(xml_support_h) $(gdb_assert_h)
|
||||
$(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h)
|
||||
xml-support.o: xml-support.c $(defs_h) $(xml_support_h) $(exceptions_h) \
|
||||
$(gdbcmd_h) $(gdb_string_h) $(gdb_expat_h) $(safe_ctype_h)
|
||||
xstormy16-tdep.o: xstormy16-tdep.c $(defs_h) $(frame_h) $(frame_base_h) \
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-02-07 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Target Description Format): Add section on XInclude.
|
||||
|
||||
2006-02-03 Nick Roberts <nickrob@snap.net.nz>
|
||||
|
||||
* gdb.texinfo (GDB/MI Miscellaneous Commands): Describe the new
|
||||
|
@ -25825,6 +25825,33 @@ The content of the @samp{<architecture>} element is an architecture
|
||||
name, from the same selection accepted by @code{set architecture}
|
||||
(@pxref{Targets, ,Specifying a Debugging Target}).
|
||||
|
||||
@subsection Inclusion
|
||||
@cindex target descriptions, inclusion
|
||||
@cindex XInclude
|
||||
@ifnotinfo
|
||||
@cindex <xi:include>
|
||||
@end ifnotinfo
|
||||
|
||||
It can sometimes be valuable to split a target description up into
|
||||
several different annexes, either for organizational purposes, or to
|
||||
share files between different possible target descriptions. You can
|
||||
divide a description into multiple files by replacing any element of
|
||||
the target description with an inclusion directive of the form:
|
||||
|
||||
@example
|
||||
<xi:include href="@var{document}"/>
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
When @value{GDBN} encounters an element of this form, it will retrieve
|
||||
the named XML @var{document}, and replace the inclusion directive with
|
||||
the contents of that document. If the current description was read
|
||||
using @samp{qXfer}, then so will be the included document;
|
||||
@var{document} will be interpreted as the name of an annex. If the
|
||||
current description was read from a file, @value{GDBN} will look for
|
||||
@var{document} as a file in the same directory where it found the
|
||||
original description.
|
||||
|
||||
|
||||
@include gpl.texi
|
||||
|
||||
|
77
gdb/features/feature_to_c.sh
Normal file
77
gdb/features/feature_to_c.sh
Normal file
@ -0,0 +1,77 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Convert text files to compilable C arrays.
|
||||
#
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GDB.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
output=$1
|
||||
shift
|
||||
|
||||
if test -z "$output" || test -z "$1"; then
|
||||
echo "Usage: $0 OUTPUTFILE INPUTFILE..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -e "$output"; then
|
||||
echo "Output file \"$output\" already exists; refusing to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for input; do
|
||||
arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
|
||||
|
||||
${AWK:-awk} 'BEGIN { n = 0
|
||||
print "static const char '$arrayname'[] = {"
|
||||
for (i = 0; i < 255; i++)
|
||||
_ord_[sprintf("%c", i)] = i
|
||||
} {
|
||||
split($0, line, "");
|
||||
printf " "
|
||||
for (i = 1; i <= length($0); i++) {
|
||||
c = line[i]
|
||||
if (c == "'\''") {
|
||||
printf "'\''\\'\'''\'', "
|
||||
} else if (c == "\\") {
|
||||
printf "'\''\\\\'\'', "
|
||||
} else if (_ord_[c] >= 32 && _ord_[c] < 127) {
|
||||
printf "'\''" c "'\'', "
|
||||
} else {
|
||||
printf "'\''\\%03o'\'', ", _ord_[c]
|
||||
}
|
||||
if (i % 10 == 0)
|
||||
printf "\n "
|
||||
}
|
||||
printf "'\''\\n'\'', \n"
|
||||
} END {
|
||||
print " 0 };"
|
||||
}' < $input >> $output
|
||||
done
|
||||
|
||||
echo >> $output
|
||||
echo "const char *const xml_builtin[][2] = {" >> $output
|
||||
|
||||
for input; do
|
||||
basename=`echo $input | sed 's,.*/,,'`
|
||||
arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
|
||||
echo " { \"$basename\", $arrayname }," >> $output
|
||||
done
|
||||
|
||||
echo " { 0, 0 }" >> $output
|
||||
echo "};" >> $output
|
@ -1,9 +1,14 @@
|
||||
<!-- Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!-- The root element of a GDB target description is <target>. -->
|
||||
|
||||
<!ELEMENT target (architecture?)>
|
||||
<!ATTLIST target
|
||||
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
|
||||
|
||||
<!ELEMENT architecture (#PCDATA)>
|
||||
|
||||
|
||||
<!ENTITY % xinclude SYSTEM "xinclude.dtd">
|
||||
%xinclude;
|
||||
|
13
gdb/features/xinclude.dtd
Normal file
13
gdb/features/xinclude.dtd
Normal file
@ -0,0 +1,13 @@
|
||||
<!-- Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!-- GDB supports a subset of XInclude. Only whole documents can
|
||||
be included, and only as XML. -->
|
||||
|
||||
<!ELEMENT xi:include (EMPTY)>
|
||||
<!ATTLIST xi:include
|
||||
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude"
|
||||
href CDATA #REQUIRED>
|
@ -1,3 +1,8 @@
|
||||
2007-02-07 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.xml/bad-include.xml, gdb.xml/inc-2.xml, gdb.xml/inc-body.xml,
|
||||
gdb.xml/includes.xml, gdb.xml/tdesc-xinclude.exp: New files.
|
||||
|
||||
2007-02-02 Denis Pilat <denis.pilat@st.com>
|
||||
|
||||
* gdb.threads/threadapply.exp: check that frame is not changed by
|
||||
|
1
gdb/testsuite/gdb.xml/bad-include.xml
Normal file
1
gdb/testsuite/gdb.xml/bad-include.xml
Normal file
@ -0,0 +1 @@
|
||||
<xi:include href="nonexistant.xml"/>
|
1
gdb/testsuite/gdb.xml/inc-2.xml
Normal file
1
gdb/testsuite/gdb.xml/inc-2.xml
Normal file
@ -0,0 +1 @@
|
||||
<xi:include href="inc-body.xml"/>
|
1
gdb/testsuite/gdb.xml/inc-body.xml
Normal file
1
gdb/testsuite/gdb.xml/inc-body.xml
Normal file
@ -0,0 +1 @@
|
||||
<architecture>invalid-body</architecture>
|
3
gdb/testsuite/gdb.xml/includes.xml
Normal file
3
gdb/testsuite/gdb.xml/includes.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<target>
|
||||
<xi:include href="inc-2.xml"/>
|
||||
</target>
|
1
gdb/testsuite/gdb.xml/loop.xml
Normal file
1
gdb/testsuite/gdb.xml/loop.xml
Normal file
@ -0,0 +1 @@
|
||||
<xi:include href="loop.xml"/>
|
54
gdb/testsuite/gdb.xml/tdesc-xinclude.exp
Normal file
54
gdb/testsuite/gdb.xml/tdesc-xinclude.exp
Normal file
@ -0,0 +1,54 @@
|
||||
# Copyright 2007 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
if {[gdb_skip_xml_test]} {
|
||||
unsupported "tdesc-errors.exp"
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_start
|
||||
|
||||
proc set_arch { srcfile errmsg } {
|
||||
global gdb_prompt
|
||||
global srcdir
|
||||
global subdir
|
||||
|
||||
# Anchor the test output, so that error messages are detected.
|
||||
set cmd "set tdesc filename $srcdir/$subdir/$srcfile"
|
||||
set msg $cmd
|
||||
set cmd_regex [string_to_regexp $cmd]
|
||||
gdb_test_multiple $cmd $msg {
|
||||
-re "^$cmd_regex\r\n$errmsg$gdb_prompt $" {
|
||||
pass $msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set common_warn "\r\nwarning: Could not load XML target description; ignoring\r\n"
|
||||
|
||||
# This file is valid, but specifies an unknown architecture.
|
||||
# We should get a warning, if we process the includes correctly.
|
||||
set_arch "includes.xml" \
|
||||
"warning:.*specified unknown architecture.* \"invalid-body\"$common_warn"
|
||||
|
||||
# This file contains a missing include. We should warn the user about
|
||||
# it.
|
||||
set_arch "bad-include.xml" \
|
||||
"warning:.*Could not load XML document \"nonexistant.xml\"$common_warn"
|
||||
|
||||
# Make sure we detect infinite loops, eventually.
|
||||
set_arch "loop.xml" \
|
||||
"warning:.*Maximum XInclude depth.*$common_warn"
|
@ -36,6 +36,10 @@ static int debug_xml;
|
||||
#include "gdb_string.h"
|
||||
#include "safe-ctype.h"
|
||||
|
||||
/* The maximum depth of <xi:include> nesting. No need to be miserly,
|
||||
we just want to avoid running out of stack on loops. */
|
||||
#define MAX_XINCLUDE_DEPTH 30
|
||||
|
||||
/* A parsing level -- used to keep track of the current element
|
||||
nesting. */
|
||||
struct scope_level
|
||||
@ -68,6 +72,10 @@ struct gdb_xml_parser
|
||||
|
||||
struct gdb_exception error; /* A thrown error, if any. */
|
||||
int last_line; /* The line of the thrown error, or 0. */
|
||||
|
||||
const char *dtd_name; /* The name of the expected / default DTD,
|
||||
if specified. */
|
||||
int is_xinclude; /* Are we the special <xi:include> parser? */
|
||||
};
|
||||
|
||||
/* Process some body text. We accumulate the text for later use; it's
|
||||
@ -152,7 +160,7 @@ gdb_xml_start_element (void *data, const XML_Char *name,
|
||||
const XML_Char **attrs)
|
||||
{
|
||||
struct gdb_xml_parser *parser = data;
|
||||
struct scope_level *scope = VEC_last (scope_level_s, parser->scopes);
|
||||
struct scope_level *scope;
|
||||
struct scope_level new_scope;
|
||||
const struct gdb_xml_element *element;
|
||||
const struct gdb_xml_attribute *attribute;
|
||||
@ -160,13 +168,13 @@ gdb_xml_start_element (void *data, const XML_Char *name,
|
||||
unsigned int seen;
|
||||
struct cleanup *back_to;
|
||||
|
||||
back_to = make_cleanup (gdb_xml_values_cleanup, &attributes);
|
||||
|
||||
/* Push an error scope. If we return or throw an exception before
|
||||
filling this in, it will tell us to ignore children of this
|
||||
element. */
|
||||
VEC_reserve (scope_level_s, parser->scopes, 1);
|
||||
scope = VEC_last (scope_level_s, parser->scopes);
|
||||
memset (&new_scope, 0, sizeof (new_scope));
|
||||
VEC_safe_push (scope_level_s, parser->scopes, &new_scope);
|
||||
VEC_quick_push (scope_level_s, parser->scopes, &new_scope);
|
||||
|
||||
gdb_xml_debug (parser, _("Entering element <%s>"), name);
|
||||
|
||||
@ -181,8 +189,21 @@ gdb_xml_start_element (void *data, const XML_Char *name,
|
||||
|
||||
if (element == NULL || element->name == NULL)
|
||||
{
|
||||
/* If we're working on XInclude, <xi:include> can be the child
|
||||
of absolutely anything. Copy the previous scope's element
|
||||
list into the new scope even if there was no match. */
|
||||
if (parser->is_xinclude)
|
||||
{
|
||||
struct scope_level *unknown_scope;
|
||||
|
||||
XML_DefaultCurrent (parser->expat_parser);
|
||||
|
||||
unknown_scope = VEC_last (scope_level_s, parser->scopes);
|
||||
unknown_scope->elements = scope->elements;
|
||||
return;
|
||||
}
|
||||
|
||||
gdb_xml_debug (parser, _("Element <%s> unknown"), name);
|
||||
do_cleanups (back_to);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -191,6 +212,8 @@ gdb_xml_start_element (void *data, const XML_Char *name,
|
||||
|
||||
scope->seen |= seen;
|
||||
|
||||
back_to = make_cleanup (gdb_xml_values_cleanup, &attributes);
|
||||
|
||||
for (attribute = element->attributes;
|
||||
attribute != NULL && attribute->name != NULL;
|
||||
attribute++)
|
||||
@ -304,7 +327,6 @@ gdb_xml_end_element (void *data, const XML_Char *name)
|
||||
struct scope_level *scope = VEC_last (scope_level_s, parser->scopes);
|
||||
const struct gdb_xml_element *element;
|
||||
unsigned int seen;
|
||||
char *body;
|
||||
|
||||
gdb_xml_debug (parser, _("Leaving element <%s>"), name);
|
||||
|
||||
@ -317,26 +339,32 @@ gdb_xml_end_element (void *data, const XML_Char *name)
|
||||
element->name);
|
||||
|
||||
/* Call the element processor. */
|
||||
if (scope->body == NULL)
|
||||
body = "";
|
||||
else
|
||||
{
|
||||
int length;
|
||||
|
||||
length = obstack_object_size (scope->body);
|
||||
obstack_1grow (scope->body, '\0');
|
||||
body = obstack_finish (scope->body);
|
||||
|
||||
/* Strip leading and trailing whitespace. */
|
||||
while (length > 0 && ISSPACE (body[length-1]))
|
||||
body[--length] = '\0';
|
||||
while (*body && ISSPACE (*body))
|
||||
body++;
|
||||
}
|
||||
|
||||
if (scope->element != NULL && scope->element->end_handler)
|
||||
scope->element->end_handler (parser, scope->element, parser->user_data,
|
||||
body);
|
||||
{
|
||||
char *body;
|
||||
|
||||
if (scope->body == NULL)
|
||||
body = "";
|
||||
else
|
||||
{
|
||||
int length;
|
||||
|
||||
length = obstack_object_size (scope->body);
|
||||
obstack_1grow (scope->body, '\0');
|
||||
body = obstack_finish (scope->body);
|
||||
|
||||
/* Strip leading and trailing whitespace. */
|
||||
while (length > 0 && ISSPACE (body[length-1]))
|
||||
body[--length] = '\0';
|
||||
while (*body && ISSPACE (*body))
|
||||
body++;
|
||||
}
|
||||
|
||||
scope->element->end_handler (parser, scope->element, parser->user_data,
|
||||
body);
|
||||
}
|
||||
else if (scope->element == NULL)
|
||||
XML_DefaultCurrent (parser->expat_parser);
|
||||
|
||||
/* Pop the scope level. */
|
||||
if (scope->body)
|
||||
@ -435,6 +463,74 @@ gdb_xml_create_parser_and_cleanup (const char *name,
|
||||
return parser;
|
||||
}
|
||||
|
||||
/* External entity handler. The only external entities we support
|
||||
are those compiled into GDB (we do not fetch entities from the
|
||||
target). */
|
||||
|
||||
static int XMLCALL
|
||||
gdb_xml_fetch_external_entity (XML_Parser expat_parser,
|
||||
const XML_Char *context,
|
||||
const XML_Char *base,
|
||||
const XML_Char *systemId,
|
||||
const XML_Char *publicId)
|
||||
{
|
||||
struct gdb_xml_parser *parser = XML_GetUserData (expat_parser);
|
||||
XML_Parser entity_parser;
|
||||
const char *text;
|
||||
enum XML_Status status;
|
||||
|
||||
if (systemId == NULL)
|
||||
{
|
||||
text = fetch_xml_builtin (parser->dtd_name);
|
||||
if (text == NULL)
|
||||
internal_error (__FILE__, __LINE__, "could not locate built-in DTD %s",
|
||||
parser->dtd_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = fetch_xml_builtin (systemId);
|
||||
if (text == NULL)
|
||||
return XML_STATUS_ERROR;
|
||||
}
|
||||
|
||||
entity_parser = XML_ExternalEntityParserCreate (expat_parser, context, NULL);
|
||||
|
||||
/* Don't use our handlers for the contents of the DTD. Just let expat
|
||||
process it. */
|
||||
XML_SetElementHandler (entity_parser, NULL, NULL);
|
||||
XML_SetDoctypeDeclHandler (entity_parser, NULL, NULL);
|
||||
XML_SetXmlDeclHandler (entity_parser, NULL);
|
||||
XML_SetDefaultHandler (entity_parser, NULL);
|
||||
XML_SetUserData (entity_parser, NULL);
|
||||
|
||||
status = XML_Parse (entity_parser, text, strlen (text), 1);
|
||||
|
||||
XML_ParserFree (entity_parser);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Associate DTD_NAME, which must be the name of a compiled-in DTD,
|
||||
with PARSER. */
|
||||
|
||||
void
|
||||
gdb_xml_use_dtd (struct gdb_xml_parser *parser, const char *dtd_name)
|
||||
{
|
||||
enum XML_Error err;
|
||||
|
||||
parser->dtd_name = dtd_name;
|
||||
|
||||
XML_SetParamEntityParsing (parser->expat_parser,
|
||||
XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
|
||||
XML_SetExternalEntityRefHandler (parser->expat_parser,
|
||||
gdb_xml_fetch_external_entity);
|
||||
|
||||
/* Even if no DTD is provided, use the built-in DTD anyway. */
|
||||
err = XML_UseForeignDTD (parser->expat_parser, XML_TRUE);
|
||||
if (err != XML_ERROR_NONE)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"XML_UseForeignDTD failed: %s", XML_ErrorString (err));
|
||||
}
|
||||
|
||||
/* Invoke PARSER on BUFFER. BUFFER is the data to parse, which
|
||||
should be NUL-terminated.
|
||||
|
||||
@ -560,6 +656,236 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser,
|
||||
memcpy (ret, &enums->value, sizeof (enums->value));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* XInclude processing. This is done as a separate step from actually
|
||||
parsing the document, so that we can produce a single combined XML
|
||||
document - e.g. to hand to a front end or to simplify comparing two
|
||||
documents. We make extensive use of XML_DefaultCurrent, to pass
|
||||
input text directly into the output without reformatting or
|
||||
requoting it.
|
||||
|
||||
We output the DOCTYPE declaration for the first document unchanged,
|
||||
if present, and discard DOCTYPEs from included documents. Only the
|
||||
one we pass through here is used when we feed the result back to
|
||||
expat. The XInclude standard explicitly does not discuss
|
||||
validation of the result; we choose to apply the same DTD applied
|
||||
to the outermost document.
|
||||
|
||||
We can not simply include the external DTD subset in the document
|
||||
as an internal subset, because <!IGNORE> and <!INCLUDE> are valid
|
||||
only in external subsets. But if we do not pass the DTD into the
|
||||
output at all, default values will not be filled in.
|
||||
|
||||
We don't pass through any <?xml> declaration because we generate
|
||||
UTF-8, not whatever the input encoding was. */
|
||||
|
||||
struct xinclude_parsing_data
|
||||
{
|
||||
/* The obstack to build the output in. */
|
||||
struct obstack obstack;
|
||||
|
||||
/* A count indicating whether we are in an element whose
|
||||
children should not be copied to the output, and if so,
|
||||
how deep we are nested. This is used for anything inside
|
||||
an xi:include, and for the DTD. */
|
||||
int skip_depth;
|
||||
|
||||
/* The number of <xi:include> elements currently being processed,
|
||||
to detect loops. */
|
||||
int include_depth;
|
||||
|
||||
/* A function to call to obtain additional features, and its
|
||||
baton. */
|
||||
xml_fetch_another fetcher;
|
||||
void *fetcher_baton;
|
||||
};
|
||||
|
||||
static void
|
||||
xinclude_start_include (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct xinclude_parsing_data *data = user_data;
|
||||
char *href = VEC_index (gdb_xml_value_s, attributes, 0)->value;
|
||||
struct cleanup *back_to;
|
||||
char *text, *output;
|
||||
int ret;
|
||||
|
||||
gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href);
|
||||
|
||||
if (data->include_depth > MAX_XINCLUDE_DEPTH)
|
||||
gdb_xml_error (parser, _("Maximum XInclude depth (%d) exceeded"),
|
||||
MAX_XINCLUDE_DEPTH);
|
||||
|
||||
text = data->fetcher (href, data->fetcher_baton);
|
||||
if (text == NULL)
|
||||
gdb_xml_error (parser, _("Could not load XML document \"%s\""), href);
|
||||
back_to = make_cleanup (xfree, text);
|
||||
|
||||
output = xml_process_xincludes (parser->name, text, data->fetcher,
|
||||
data->fetcher_baton,
|
||||
data->include_depth + 1);
|
||||
if (output == NULL)
|
||||
gdb_xml_error (parser, _("Parsing \"%s\" failed"), href);
|
||||
|
||||
obstack_grow (&data->obstack, output, strlen (output));
|
||||
xfree (output);
|
||||
|
||||
do_cleanups (back_to);
|
||||
|
||||
data->skip_depth++;
|
||||
}
|
||||
|
||||
static void
|
||||
xinclude_end_include (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, const char *body_text)
|
||||
{
|
||||
struct xinclude_parsing_data *data = user_data;
|
||||
|
||||
data->skip_depth--;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
xml_xinclude_default (void *data_, const XML_Char *s, int len)
|
||||
{
|
||||
struct gdb_xml_parser *parser = data_;
|
||||
struct xinclude_parsing_data *data = parser->user_data;
|
||||
|
||||
/* If we are inside of e.g. xi:include or the DTD, don't save this
|
||||
string. */
|
||||
if (data->skip_depth)
|
||||
return;
|
||||
|
||||
/* Otherwise just add it to the end of the document we're building
|
||||
up. */
|
||||
obstack_grow (&data->obstack, s, len);
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
xml_xinclude_start_doctype (void *data_, const XML_Char *doctypeName,
|
||||
const XML_Char *sysid, const XML_Char *pubid,
|
||||
int has_internal_subset)
|
||||
{
|
||||
struct gdb_xml_parser *parser = data_;
|
||||
struct xinclude_parsing_data *data = parser->user_data;
|
||||
|
||||
/* Don't print out the doctype, or the contents of the DTD internal
|
||||
subset, if any. */
|
||||
data->skip_depth++;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
xml_xinclude_end_doctype (void *data_)
|
||||
{
|
||||
struct gdb_xml_parser *parser = data_;
|
||||
struct xinclude_parsing_data *data = parser->user_data;
|
||||
|
||||
data->skip_depth--;
|
||||
}
|
||||
|
||||
static void XMLCALL
|
||||
xml_xinclude_xml_decl (void *data_, const XML_Char *version,
|
||||
const XML_Char *encoding, int standalone)
|
||||
{
|
||||
/* Do nothing - this function prevents the default handler from
|
||||
being called, thus suppressing the XML declaration from the
|
||||
output. */
|
||||
}
|
||||
|
||||
static void
|
||||
xml_xinclude_cleanup (void *data_)
|
||||
{
|
||||
struct xinclude_parsing_data *data = data_;
|
||||
|
||||
obstack_free (&data->obstack, NULL);
|
||||
xfree (data);
|
||||
}
|
||||
|
||||
const struct gdb_xml_attribute xinclude_attributes[] = {
|
||||
{ "href", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element xinclude_elements[] = {
|
||||
{ "http://www.w3.org/2001/XInclude!include", xinclude_attributes, NULL,
|
||||
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
|
||||
xinclude_start_include, xinclude_end_include },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
/* The main entry point for <xi:include> processing. */
|
||||
|
||||
char *
|
||||
xml_process_xincludes (const char *name, const char *text,
|
||||
xml_fetch_another fetcher, void *fetcher_baton,
|
||||
int depth)
|
||||
{
|
||||
enum XML_Error err;
|
||||
struct gdb_xml_parser *parser;
|
||||
struct xinclude_parsing_data *data;
|
||||
struct cleanup *back_to;
|
||||
char *result = NULL;
|
||||
|
||||
data = XZALLOC (struct xinclude_parsing_data);
|
||||
obstack_init (&data->obstack);
|
||||
back_to = make_cleanup (xml_xinclude_cleanup, data);
|
||||
|
||||
parser = gdb_xml_create_parser_and_cleanup (name, xinclude_elements, data);
|
||||
parser->is_xinclude = 1;
|
||||
|
||||
data->include_depth = depth;
|
||||
data->fetcher = fetcher;
|
||||
data->fetcher_baton = fetcher_baton;
|
||||
|
||||
XML_SetCharacterDataHandler (parser->expat_parser, NULL);
|
||||
XML_SetDefaultHandler (parser->expat_parser, xml_xinclude_default);
|
||||
|
||||
/* Always discard the XML version declarations; the only important
|
||||
thing this provides is encoding, and our result will have been
|
||||
converted to UTF-8. */
|
||||
XML_SetXmlDeclHandler (parser->expat_parser, xml_xinclude_xml_decl);
|
||||
|
||||
if (depth > 0)
|
||||
/* Discard the doctype for included documents. */
|
||||
XML_SetDoctypeDeclHandler (parser->expat_parser,
|
||||
xml_xinclude_start_doctype,
|
||||
xml_xinclude_end_doctype);
|
||||
|
||||
gdb_xml_use_dtd (parser, "xinclude.dtd");
|
||||
|
||||
if (gdb_xml_parse (parser, text) == 0)
|
||||
{
|
||||
obstack_1grow (&data->obstack, '\0');
|
||||
result = xstrdup (obstack_finish (&data->obstack));
|
||||
|
||||
if (depth == 0)
|
||||
gdb_xml_debug (parser, _("XInclude processing succeeded:\n%s"),
|
||||
result);
|
||||
}
|
||||
else
|
||||
result = NULL;
|
||||
|
||||
do_cleanups (back_to);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Return an XML document which was compiled into GDB, from
|
||||
the given FILENAME, or NULL if the file was not compiled in. */
|
||||
|
||||
const char *
|
||||
fetch_xml_builtin (const char *filename)
|
||||
{
|
||||
const char *(*p)[2];
|
||||
|
||||
for (p = xml_builtin; (*p)[0]; p++)
|
||||
if (strcmp ((*p)[0], filename) == 0)
|
||||
return (*p)[1];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBEXPAT */
|
||||
|
||||
|
@ -30,6 +30,35 @@ struct gdb_xml_parser;
|
||||
struct gdb_xml_element;
|
||||
struct gdb_xml_attribute;
|
||||
|
||||
/* Support for XInclude. */
|
||||
|
||||
/* Callback to fetch a new XML file, based on the provided HREF. */
|
||||
|
||||
typedef char *(*xml_fetch_another) (const char *href, void *baton);
|
||||
|
||||
/* Return a new string which is the expansion of TEXT after processing
|
||||
<xi:include> tags. FETCHER will be called (with FETCHER_BATON) to
|
||||
retrieve any new files. DEPTH should be zero on the initial call.
|
||||
|
||||
On failure, this function uses NAME in a warning and returns NULL.
|
||||
It may throw an exception, but does not for XML parsing
|
||||
problems. */
|
||||
|
||||
char *xml_process_xincludes (const char *name, const char *text,
|
||||
xml_fetch_another fetcher, void *fetcher_baton,
|
||||
int depth);
|
||||
|
||||
/* Return an XML document which was compiled into GDB, from
|
||||
the given FILENAME, or NULL if the file was not compiled in. */
|
||||
|
||||
const char *fetch_xml_builtin (const char *filename);
|
||||
|
||||
/* The text of compiled-in XML documents, from xml-builtin.c
|
||||
(generated). */
|
||||
extern const char *xml_builtin[][2];
|
||||
|
||||
/* Simplified XML parser infrastructure. */
|
||||
|
||||
/* A name and value pair, used to record parsed attributes. */
|
||||
|
||||
struct gdb_xml_value
|
||||
@ -140,6 +169,11 @@ struct gdb_xml_parser *gdb_xml_create_parser_and_cleanup
|
||||
(const char *name, const struct gdb_xml_element *elements,
|
||||
void *user_data);
|
||||
|
||||
/* Associate DTD_NAME, which must be the name of a compiled-in DTD,
|
||||
with PARSER. */
|
||||
|
||||
void gdb_xml_use_dtd (struct gdb_xml_parser *parser, const char *dtd_name);
|
||||
|
||||
/* Invoke PARSER on BUFFER. BUFFER is the data to parse, which
|
||||
should be NUL-terminated.
|
||||
|
||||
|
106
gdb/xml-tdesc.c
106
gdb/xml-tdesc.c
@ -28,6 +28,8 @@
|
||||
#include "xml-support.h"
|
||||
#include "xml-tdesc.h"
|
||||
|
||||
#include "filenames.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#if !defined(HAVE_LIBEXPAT)
|
||||
@ -36,7 +38,8 @@
|
||||
an XML parser. */
|
||||
|
||||
static struct target_desc *
|
||||
tdesc_parse_xml (const char *document)
|
||||
tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
|
||||
void *fetcher_baton)
|
||||
{
|
||||
static int have_warned;
|
||||
|
||||
@ -94,22 +97,33 @@ const struct gdb_xml_element tdesc_elements[] = {
|
||||
/* Parse DOCUMENT into a target description and return it. */
|
||||
|
||||
static struct target_desc *
|
||||
tdesc_parse_xml (const char *document)
|
||||
tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
|
||||
void *fetcher_baton)
|
||||
{
|
||||
struct cleanup *back_to, *result_cleanup;
|
||||
struct gdb_xml_parser *parser;
|
||||
struct tdesc_parsing_data data;
|
||||
char *expanded_text;
|
||||
|
||||
memset (&data, 0, sizeof (struct tdesc_parsing_data));
|
||||
/* Expand all XInclude directives. */
|
||||
expanded_text = xml_process_xincludes (_("target description"),
|
||||
document, fetcher, fetcher_baton, 0);
|
||||
if (expanded_text == NULL)
|
||||
{
|
||||
warning (_("Could not load XML target description; ignoring"));
|
||||
return NULL;
|
||||
}
|
||||
back_to = make_cleanup (xfree, expanded_text);
|
||||
|
||||
back_to = make_cleanup (null_cleanup, NULL);
|
||||
parser = gdb_xml_create_parser_and_cleanup (_("target description"),
|
||||
tdesc_elements, &data);
|
||||
gdb_xml_use_dtd (parser, "gdb-target.dtd");
|
||||
|
||||
memset (&data, 0, sizeof (struct tdesc_parsing_data));
|
||||
data.tdesc = allocate_target_description ();
|
||||
result_cleanup = make_cleanup_free_target_description (data.tdesc);
|
||||
|
||||
if (gdb_xml_parse (parser, document) == 0)
|
||||
if (gdb_xml_parse (parser, expanded_text) == 0)
|
||||
{
|
||||
/* Parsed successfully. */
|
||||
discard_cleanups (result_cleanup);
|
||||
@ -123,7 +137,6 @@ tdesc_parse_xml (const char *document)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBEXPAT */
|
||||
|
||||
|
||||
@ -139,19 +152,28 @@ do_cleanup_fclose (void *file)
|
||||
the text. If something goes wrong, return NULL and warn. */
|
||||
|
||||
static char *
|
||||
fetch_xml_from_file (const char *filename)
|
||||
fetch_xml_from_file (const char *filename, void *baton)
|
||||
{
|
||||
const char *dirname = baton;
|
||||
FILE *file;
|
||||
struct cleanup *back_to;
|
||||
char *text;
|
||||
size_t len, offset;
|
||||
|
||||
file = fopen (filename, FOPEN_RT);
|
||||
if (file == NULL)
|
||||
if (dirname && *dirname)
|
||||
{
|
||||
warning (_("Could not open \"%s\""), filename);
|
||||
return NULL;
|
||||
char *fullname = concat (dirname, "/", filename, NULL);
|
||||
if (fullname == NULL)
|
||||
nomem (0);
|
||||
file = fopen (fullname, FOPEN_RT);
|
||||
xfree (fullname);
|
||||
}
|
||||
else
|
||||
file = fopen (filename, FOPEN_RT);
|
||||
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
|
||||
back_to = make_cleanup (do_cleanup_fclose, file);
|
||||
|
||||
/* Read in the whole file, one chunk at a time. */
|
||||
@ -198,18 +220,67 @@ file_read_description_xml (const char *filename)
|
||||
struct target_desc *tdesc;
|
||||
char *tdesc_str;
|
||||
struct cleanup *back_to;
|
||||
const char *base;
|
||||
char *dirname;
|
||||
|
||||
tdesc_str = fetch_xml_from_file (filename);
|
||||
tdesc_str = fetch_xml_from_file (filename, NULL);
|
||||
if (tdesc_str == NULL)
|
||||
return NULL;
|
||||
{
|
||||
warning (_("Could not open \"%s\""), filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
back_to = make_cleanup (xfree, tdesc_str);
|
||||
tdesc = tdesc_parse_xml (tdesc_str);
|
||||
|
||||
/* Simple, portable version of dirname that does not modify its
|
||||
argument. */
|
||||
base = lbasename (filename);
|
||||
while (base > filename && IS_DIR_SEPARATOR (base[-1]))
|
||||
--base;
|
||||
if (base > filename)
|
||||
{
|
||||
dirname = xmalloc (base - filename + 2);
|
||||
memcpy (dirname, filename, base - filename);
|
||||
|
||||
/* On DOS based file systems, convert "d:foo" to "d:.", so that
|
||||
we create "d:./bar" later instead of the (different)
|
||||
"d:/bar". */
|
||||
if (base - filename == 2 && IS_ABSOLUTE_PATH (base)
|
||||
&& !IS_DIR_SEPARATOR (filename[0]))
|
||||
dirname[base++ - filename] = '.';
|
||||
|
||||
dirname[base - filename] = '\0';
|
||||
make_cleanup (xfree, dirname);
|
||||
}
|
||||
else
|
||||
dirname = NULL;
|
||||
|
||||
tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname);
|
||||
do_cleanups (back_to);
|
||||
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
/* Read a string representation of available features from the target,
|
||||
using TARGET_OBJECT_AVAILABLE_FEATURES. The returned string is
|
||||
malloc allocated and NUL-terminated. NAME should be a non-NULL
|
||||
string identifying the XML document we want; the top level document
|
||||
is "target.xml". Other calls may be performed for the DTD or
|
||||
for <xi:include>. */
|
||||
|
||||
static char *
|
||||
fetch_available_features_from_target (const char *name, void *baton_)
|
||||
{
|
||||
struct target_ops *ops = baton_;
|
||||
|
||||
/* Read this object as a string. This ensures that a NUL
|
||||
terminator is added. */
|
||||
return target_read_stralloc (ops,
|
||||
TARGET_OBJECT_AVAILABLE_FEATURES,
|
||||
name);
|
||||
}
|
||||
|
||||
|
||||
/* Read an XML target description using OPS. Parse it, and return the
|
||||
parsed description. */
|
||||
|
||||
@ -220,13 +291,14 @@ target_read_description_xml (struct target_ops *ops)
|
||||
char *tdesc_str;
|
||||
struct cleanup *back_to;
|
||||
|
||||
tdesc_str = target_read_stralloc (ops, TARGET_OBJECT_AVAILABLE_FEATURES,
|
||||
"target.xml");
|
||||
tdesc_str = fetch_available_features_from_target ("target.xml", ops);
|
||||
if (tdesc_str == NULL)
|
||||
return NULL;
|
||||
|
||||
back_to = make_cleanup (xfree, tdesc_str);
|
||||
tdesc = tdesc_parse_xml (tdesc_str);
|
||||
tdesc = tdesc_parse_xml (tdesc_str,
|
||||
fetch_available_features_from_target,
|
||||
ops);
|
||||
do_cleanups (back_to);
|
||||
|
||||
return tdesc;
|
||||
|
Loading…
Reference in New Issue
Block a user