* 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:
Daniel Jacobowitz 2007-02-07 22:48:06 +00:00
parent 7bd1c9613d
commit 108546a0ea
17 changed files with 721 additions and 47 deletions

View File

@ -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

View File

@ -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) \

View File

@ -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

View File

@ -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

View 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

View File

@ -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
View 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>

View File

@ -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

View File

@ -0,0 +1 @@
<xi:include href="nonexistant.xml"/>

View File

@ -0,0 +1 @@
<xi:include href="inc-body.xml"/>

View File

@ -0,0 +1 @@
<architecture>invalid-body</architecture>

View File

@ -0,0 +1,3 @@
<target>
<xi:include href="inc-2.xml"/>
</target>

View File

@ -0,0 +1 @@
<xi:include href="loop.xml"/>

View 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"

View File

@ -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 */

View File

@ -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.

View File

@ -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;