Commit 108546a0 authored by Daniel Jacobowitz's avatar Daniel Jacobowitz
Browse files

* 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.
parent 7bd1c961
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) \
......
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
 
......
#!/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
<!-- 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;
<!-- 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>
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
......
<xi:include href="nonexistant.xml"/>
<xi:include href="inc-body.xml"/>
<architecture>invalid-body</architecture>
<target>
<xi:include href="inc-2.xml"/>
</target>
<xi:include href="loop.xml"/>
# 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
if (scope->element != NULL && scope->element->end_handler)
{
int length;
char *body;
length = obstack_object_size (scope->body);
obstack_1grow (scope->body, '\0');
body = obstack_finish (scope->body);
if (scope->body == NULL)
body = "";
else
{
int length;
/* Strip leading and trailing whitespace. */
while (length > 0 && ISSPACE (body[length-1]))
body[--length] = '\0';
while (*body && ISSPACE (*body))
body++;
}
length = obstack_object_size (scope->body);
obstack_1grow (scope->body, '\0');
body = obstack_finish (scope->body);
if (scope->element != NULL && scope->element->end_handler)
scope->element->end_handler (parser, scope->element, parser->user_data,
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);
}