]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/xml-support.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / xml-support.c
CommitLineData
fd79ecee
DJ
1/* Helper routines for parsing XML using Expat.
2
213516ef 3 Copyright (C) 2006-2023 Free Software Foundation, Inc.
fd79ecee
DJ
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
fd79ecee
DJ
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
fd79ecee
DJ
19
20#include "defs.h"
e776119f 21#include "gdbcmd.h"
fec4e896 22#include "xml-builtin.h"
05a4558a 23#include "xml-support.h"
268a13a5 24#include "gdbsupport/filestuff.h"
05a4558a 25#include "safe-ctype.h"
a7fc9b61 26#include <vector>
bd8a901f 27#include <string>
e776119f
DJ
28
29/* Debugging flag. */
491144b5 30static bool debug_xml;
fd79ecee
DJ
31
32/* The contents of this file are only useful if XML support is
33 available. */
34#ifdef HAVE_LIBEXPAT
35
dbc981de 36#include "gdb_expat.h"
e776119f 37
108546a0
DJ
38/* The maximum depth of <xi:include> nesting. No need to be miserly,
39 we just want to avoid running out of stack on loops. */
40#define MAX_XINCLUDE_DEPTH 30
41
123dc839
DJ
42/* Simplified XML parser infrastructure. */
43
e776119f
DJ
44/* A parsing level -- used to keep track of the current element
45 nesting. */
46struct scope_level
47{
a7fc9b61
PA
48 explicit scope_level (const gdb_xml_element *elements_ = NULL)
49 : elements (elements_),
50 element (NULL),
bd8a901f 51 seen (0)
a7fc9b61
PA
52 {}
53
e776119f
DJ
54 /* Elements we allow at this level. */
55 const struct gdb_xml_element *elements;
56
57 /* The element which we are within. */
58 const struct gdb_xml_element *element;
59
60 /* Mask of which elements we've seen at this level (used for
61 optional and repeatable checking). */
62 unsigned int seen;
63
bd8a901f
PA
64 /* Body text accumulation. */
65 std::string body;
e776119f 66};
e776119f
DJ
67
68/* The parser itself, and our additional state. */
69struct gdb_xml_parser
70{
010151c9
PA
71 gdb_xml_parser (const char *name,
72 const gdb_xml_element *elements,
73 void *user_data);
74 ~gdb_xml_parser();
75
4895cde2
PA
76 /* Associate DTD_NAME, which must be the name of a compiled-in DTD,
77 with the parser. */
78 void use_dtd (const char *dtd_name);
79
80 /* Return the name of the expected / default DTD, if specified. */
81 const char *dtd_name ()
82 { return m_dtd_name; }
83
84 /* Invoke the parser on BUFFER. BUFFER is the data to parse, which
85 should be NUL-terminated.
86
87 The return value is 0 for success or -1 for error. It may throw,
88 but only if something unexpected goes wrong during parsing; parse
89 errors will be caught, warned about, and reported as failure. */
90 int parse (const char *buffer);
91
92 /* Issue a debugging message. */
93 void vdebug (const char *format, va_list ap)
94 ATTRIBUTE_PRINTF (2, 0);
95
96 /* Issue an error message, and stop parsing. */
97 void verror (const char *format, va_list ap)
98 ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0);
99
100 void body_text (const XML_Char *text, int length);
101 void start_element (const XML_Char *name, const XML_Char **attrs);
102 void end_element (const XML_Char *name);
103
104 /* Return the name of this parser. */
105 const char *name ()
106 { return m_name; }
107
108 /* Return the user's callback data, for handlers. */
109 void *user_data ()
110 { return m_user_data; };
111
112 /* Are we the special <xi:include> parser? */
113 void set_is_xinclude (bool is_xinclude)
114 { m_is_xinclude = is_xinclude; }
115
116 /* A thrown error, if any. */
94aeb44b 117 void set_error (gdb_exception &&error)
4895cde2 118 {
94aeb44b 119 m_error = std::move (error);
4895cde2
PA
120#ifdef HAVE_XML_STOPPARSER
121 XML_StopParser (m_expat_parser, XML_FALSE);
122#endif
123 }
124
125 /* Return the underlying expat parser. */
126 XML_Parser expat_parser ()
127 { return m_expat_parser; }
128
129private:
130 /* The underlying expat parser. */
131 XML_Parser m_expat_parser;
132
133 /* Name of this parser. */
134 const char *m_name;
e776119f 135
4895cde2
PA
136 /* The user's callback data, for handlers. */
137 void *m_user_data;
e776119f 138
a7fc9b61 139 /* Scoping stack. */
4895cde2 140 std::vector<scope_level> m_scopes;
e776119f 141
4895cde2
PA
142/* A thrown error, if any. */
143 struct gdb_exception m_error;
108546a0 144
4895cde2
PA
145 /* The line of the thrown error, or 0. */
146 int m_last_line;
147
148 /* The name of the expected / default DTD, if specified. */
149 const char *m_dtd_name;
150
151 /* Are we the special <xi:include> parser? */
152 bool m_is_xinclude;
e776119f
DJ
153};
154
155/* Process some body text. We accumulate the text for later use; it's
156 wrong to do anything with it immediately, because a single block of
157 text might be broken up into multiple calls to this function. */
158
4895cde2
PA
159void
160gdb_xml_parser::body_text (const XML_Char *text, int length)
161{
162 if (m_error.reason < 0)
163 return;
164
165 scope_level &scope = m_scopes.back ();
166 scope.body.append (text, length);
167}
168
e776119f
DJ
169static void
170gdb_xml_body_text (void *data, const XML_Char *text, int length)
171{
19ba03f4 172 struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
e776119f 173
4895cde2 174 parser->body_text (text, length);
e776119f 175}
fd79ecee 176
e776119f 177/* Issue a debugging message from one of PARSER's handlers. */
fd79ecee 178
e776119f 179void
4895cde2 180gdb_xml_parser::vdebug (const char *format, va_list ap)
e776119f 181{
4895cde2 182 int line = XML_GetCurrentLineNumber (m_expat_parser);
e776119f 183
467dc1e2 184 std::string message = string_vprintf (format, ap);
e776119f 185 if (line)
6cb06a8c
TT
186 gdb_printf (gdb_stderr, "%s (line %d): %s\n",
187 m_name, line, message.c_str ());
e776119f 188 else
6cb06a8c
TT
189 gdb_printf (gdb_stderr, "%s: %s\n",
190 m_name, message.c_str ());
e776119f
DJ
191}
192
4895cde2
PA
193void
194gdb_xml_debug (struct gdb_xml_parser *parser, const char *format, ...)
195{
196 if (!debug_xml)
197 return;
198
199 va_list ap;
200 va_start (ap, format);
201 parser->vdebug (format, ap);
202 va_end (ap);
203}
204
e776119f
DJ
205/* Issue an error message from one of PARSER's handlers, and stop
206 parsing. */
207
4895cde2
PA
208void
209gdb_xml_parser::verror (const char *format, va_list ap)
210{
211 int line = XML_GetCurrentLineNumber (m_expat_parser);
212
213 m_last_line = line;
214 throw_verror (XML_PARSE_ERROR, format, ap);
215}
216
e776119f
DJ
217void
218gdb_xml_error (struct gdb_xml_parser *parser, const char *format, ...)
219{
e776119f 220 va_list ap;
e776119f 221 va_start (ap, format);
4895cde2
PA
222 parser->verror (format, ap);
223 va_end (ap);
e776119f
DJ
224}
225
3d2c1d41
PA
226/* Find the attribute named NAME in the set of parsed attributes
227 ATTRIBUTES. Returns NULL if not found. */
228
229struct gdb_xml_value *
4d0fdd9b
SM
230xml_find_attribute (std::vector<gdb_xml_value> &attributes,
231 const char *name)
3d2c1d41 232{
4d0fdd9b
SM
233 for (gdb_xml_value &value : attributes)
234 if (strcmp (value.name, name) == 0)
235 return &value;
3d2c1d41
PA
236
237 return NULL;
238}
239
4895cde2
PA
240/* Handle the start of an element. NAME is the element, and ATTRS are
241 the names and values of this element's attributes. */
e776119f 242
4895cde2
PA
243void
244gdb_xml_parser::start_element (const XML_Char *name,
245 const XML_Char **attrs)
fd79ecee 246{
4895cde2
PA
247 if (m_error.reason < 0)
248 return;
249
e776119f
DJ
250 const struct gdb_xml_element *element;
251 const struct gdb_xml_attribute *attribute;
e776119f 252 unsigned int seen;
e776119f 253
e776119f
DJ
254 /* Push an error scope. If we return or throw an exception before
255 filling this in, it will tell us to ignore children of this
a7fc9b61
PA
256 element. Note we don't take a reference to the element yet
257 because further below we'll process the element which may recurse
258 back here and push more elements to the vector. When the
259 recursion unrolls all such elements will have been popped back
260 already, but if one of those pushes reallocates the vector,
261 previous element references will be invalidated. */
4895cde2 262 m_scopes.emplace_back ();
a7fc9b61
PA
263
264 /* Get a reference to the current scope. */
4895cde2 265 scope_level &scope = m_scopes[m_scopes.size () - 2];
e776119f 266
4895cde2 267 gdb_xml_debug (this, _("Entering element <%s>"), name);
e776119f
DJ
268
269 /* Find this element in the list of the current scope's allowed
270 children. Record that we've seen it. */
271
272 seen = 1;
a7fc9b61 273 for (element = scope.elements; element && element->name;
e776119f
DJ
274 element++, seen <<= 1)
275 if (strcmp (element->name, name) == 0)
276 break;
277
278 if (element == NULL || element->name == NULL)
279 {
108546a0
DJ
280 /* If we're working on XInclude, <xi:include> can be the child
281 of absolutely anything. Copy the previous scope's element
282 list into the new scope even if there was no match. */
4895cde2 283 if (m_is_xinclude)
108546a0 284 {
4895cde2 285 XML_DefaultCurrent (m_expat_parser);
108546a0 286
4895cde2 287 scope_level &unknown_scope = m_scopes.back ();
a7fc9b61 288 unknown_scope.elements = scope.elements;
108546a0
DJ
289 return;
290 }
291
4895cde2 292 gdb_xml_debug (this, _("Element <%s> unknown"), name);
e776119f
DJ
293 return;
294 }
295
a7fc9b61 296 if (!(element->flags & GDB_XML_EF_REPEATABLE) && (seen & scope.seen))
4895cde2 297 gdb_xml_error (this, _("Element <%s> only expected once"), name);
e776119f 298
a7fc9b61 299 scope.seen |= seen;
e776119f 300
4d0fdd9b 301 std::vector<gdb_xml_value> attributes;
108546a0 302
e776119f
DJ
303 for (attribute = element->attributes;
304 attribute != NULL && attribute->name != NULL;
305 attribute++)
306 {
307 const char *val = NULL;
308 const XML_Char **p;
309 void *parsed_value;
e776119f
DJ
310
311 for (p = attrs; *p != NULL; p += 2)
312 if (!strcmp (attribute->name, p[0]))
313 {
314 val = p[1];
315 break;
316 }
317
318 if (*p != NULL && val == NULL)
319 {
4895cde2 320 gdb_xml_debug (this, _("Attribute \"%s\" missing a value"),
e776119f
DJ
321 attribute->name);
322 continue;
323 }
324
325 if (*p == NULL && !(attribute->flags & GDB_XML_AF_OPTIONAL))
326 {
4895cde2 327 gdb_xml_error (this, _("Required attribute \"%s\" of "
e776119f
DJ
328 "<%s> not specified"),
329 attribute->name, element->name);
330 continue;
331 }
332
333 if (*p == NULL)
334 continue;
335
4895cde2 336 gdb_xml_debug (this, _("Parsing attribute %s=\"%s\""),
e776119f
DJ
337 attribute->name, val);
338
339 if (attribute->handler)
4895cde2 340 parsed_value = attribute->handler (this, attribute, val);
e776119f
DJ
341 else
342 parsed_value = xstrdup (val);
343
4d0fdd9b 344 attributes.emplace_back (attribute->name, parsed_value);
e776119f
DJ
345 }
346
347 /* Check for unrecognized attributes. */
348 if (debug_xml)
fd79ecee 349 {
e776119f
DJ
350 const XML_Char **p;
351
352 for (p = attrs; *p != NULL; p += 2)
353 {
354 for (attribute = element->attributes;
355 attribute != NULL && attribute->name != NULL;
356 attribute++)
357 if (strcmp (attribute->name, *p) == 0)
358 break;
359
360 if (attribute == NULL || attribute->name == NULL)
4895cde2 361 gdb_xml_debug (this, _("Ignoring unknown attribute %s"), *p);
e776119f
DJ
362 }
363 }
364
365 /* Call the element handler if there is one. */
366 if (element->start_handler)
4895cde2 367 element->start_handler (this, element, m_user_data, attributes);
e776119f 368
a7fc9b61
PA
369 /* Fill in a new scope level. Note that we must delay getting a
370 back reference till here because above we might have recursed,
371 which may have reallocated the vector which invalidates
372 iterators/pointers/references. */
4895cde2 373 scope_level &new_scope = m_scopes.back ();
a7fc9b61
PA
374 new_scope.element = element;
375 new_scope.elements = element->children;
e776119f
DJ
376}
377
378/* Wrapper for gdb_xml_start_element, to prevent throwing exceptions
379 through expat. */
380
381static void
382gdb_xml_start_element_wrapper (void *data, const XML_Char *name,
383 const XML_Char **attrs)
384{
19ba03f4 385 struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
e776119f 386
a70b8144 387 try
e776119f 388 {
4895cde2 389 parser->start_element (name, attrs);
e776119f 390 }
94aeb44b 391 catch (gdb_exception &ex)
e776119f 392 {
94aeb44b 393 parser->set_error (std::move (ex));
fd79ecee 394 }
e776119f
DJ
395}
396
4895cde2 397/* Handle the end of an element. NAME is the current element. */
e776119f 398
4895cde2
PA
399void
400gdb_xml_parser::end_element (const XML_Char *name)
e776119f 401{
4895cde2
PA
402 if (m_error.reason < 0)
403 return;
404
405 struct scope_level *scope = &m_scopes.back ();
e776119f
DJ
406 const struct gdb_xml_element *element;
407 unsigned int seen;
e776119f 408
4895cde2 409 gdb_xml_debug (this, _("Leaving element <%s>"), name);
e776119f
DJ
410
411 for (element = scope->elements, seen = 1;
412 element != NULL && element->name != NULL;
413 element++, seen <<= 1)
414 if ((scope->seen & seen) == 0
415 && (element->flags & GDB_XML_EF_OPTIONAL) == 0)
4895cde2 416 gdb_xml_error (this, _("Required element <%s> is missing"),
e776119f
DJ
417 element->name);
418
581e13c1 419 /* Call the element processor. */
108546a0 420 if (scope->element != NULL && scope->element->end_handler)
e776119f 421 {
bd8a901f 422 const char *body;
e776119f 423
bd8a901f
PA
424 if (scope->body.empty ())
425 body = "";
108546a0
DJ
426 else
427 {
428 int length;
e776119f 429
bd8a901f
PA
430 length = scope->body.size ();
431 body = scope->body.c_str ();
e776119f 432
108546a0 433 /* Strip leading and trailing whitespace. */
bd8a901f
PA
434 while (length > 0 && ISSPACE (body[length - 1]))
435 length--;
436 scope->body.erase (length);
108546a0
DJ
437 while (*body && ISSPACE (*body))
438 body++;
439 }
440
4895cde2
PA
441 scope->element->end_handler (this, scope->element,
442 m_user_data, body);
108546a0
DJ
443 }
444 else if (scope->element == NULL)
4895cde2 445 XML_DefaultCurrent (m_expat_parser);
e776119f
DJ
446
447 /* Pop the scope level. */
4895cde2 448 m_scopes.pop_back ();
e776119f
DJ
449}
450
451/* Wrapper for gdb_xml_end_element, to prevent throwing exceptions
452 through expat. */
453
454static void
455gdb_xml_end_element_wrapper (void *data, const XML_Char *name)
456{
19ba03f4 457 struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
e776119f 458
a70b8144 459 try
e776119f 460 {
4895cde2 461 parser->end_element (name);
e776119f 462 }
94aeb44b 463 catch (gdb_exception &ex)
e776119f 464 {
94aeb44b 465 parser->set_error (std::move (ex));
e776119f
DJ
466 }
467}
468
469/* Free a parser and all its associated state. */
470
010151c9 471gdb_xml_parser::~gdb_xml_parser ()
e776119f 472{
4895cde2 473 XML_ParserFree (m_expat_parser);
e776119f
DJ
474}
475
010151c9
PA
476/* Initialize a parser. */
477
4895cde2 478gdb_xml_parser::gdb_xml_parser (const char *name,
010151c9 479 const gdb_xml_element *elements,
4895cde2
PA
480 void *user_data)
481 : m_name (name),
482 m_user_data (user_data),
4895cde2
PA
483 m_last_line (0),
484 m_dtd_name (NULL),
485 m_is_xinclude (false)
486{
487 m_expat_parser = XML_ParserCreateNS (NULL, '!');
488 if (m_expat_parser == NULL)
010151c9 489 malloc_failure (0);
e776119f 490
4895cde2 491 XML_SetUserData (m_expat_parser, this);
e776119f
DJ
492
493 /* Set the callbacks. */
4895cde2 494 XML_SetElementHandler (m_expat_parser, gdb_xml_start_element_wrapper,
e776119f 495 gdb_xml_end_element_wrapper);
4895cde2 496 XML_SetCharacterDataHandler (m_expat_parser, gdb_xml_body_text);
e776119f
DJ
497
498 /* Initialize the outer scope. */
4895cde2 499 m_scopes.emplace_back (elements);
efc0eabd
PA
500}
501
108546a0
DJ
502/* External entity handler. The only external entities we support
503 are those compiled into GDB (we do not fetch entities from the
504 target). */
505
506static int XMLCALL
507gdb_xml_fetch_external_entity (XML_Parser expat_parser,
508 const XML_Char *context,
509 const XML_Char *base,
510 const XML_Char *systemId,
511 const XML_Char *publicId)
512{
108546a0
DJ
513 XML_Parser entity_parser;
514 const char *text;
515 enum XML_Status status;
516
517 if (systemId == NULL)
518 {
4895cde2
PA
519 gdb_xml_parser *parser
520 = (gdb_xml_parser *) XML_GetUserData (expat_parser);
521
522 text = fetch_xml_builtin (parser->dtd_name ());
108546a0 523 if (text == NULL)
f34652de 524 internal_error (_("could not locate built-in DTD %s"),
4895cde2 525 parser->dtd_name ());
108546a0
DJ
526 }
527 else
528 {
529 text = fetch_xml_builtin (systemId);
530 if (text == NULL)
531 return XML_STATUS_ERROR;
532 }
533
4895cde2
PA
534 entity_parser = XML_ExternalEntityParserCreate (expat_parser,
535 context, NULL);
108546a0
DJ
536
537 /* Don't use our handlers for the contents of the DTD. Just let expat
538 process it. */
539 XML_SetElementHandler (entity_parser, NULL, NULL);
540 XML_SetDoctypeDeclHandler (entity_parser, NULL, NULL);
541 XML_SetXmlDeclHandler (entity_parser, NULL);
542 XML_SetDefaultHandler (entity_parser, NULL);
543 XML_SetUserData (entity_parser, NULL);
544
545 status = XML_Parse (entity_parser, text, strlen (text), 1);
546
547 XML_ParserFree (entity_parser);
548 return status;
549}
550
108546a0 551void
4895cde2 552gdb_xml_parser::use_dtd (const char *dtd_name)
108546a0
DJ
553{
554 enum XML_Error err;
555
4895cde2 556 m_dtd_name = dtd_name;
108546a0 557
4895cde2 558 XML_SetParamEntityParsing (m_expat_parser,
108546a0 559 XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
4895cde2 560 XML_SetExternalEntityRefHandler (m_expat_parser,
108546a0
DJ
561 gdb_xml_fetch_external_entity);
562
563 /* Even if no DTD is provided, use the built-in DTD anyway. */
4895cde2 564 err = XML_UseForeignDTD (m_expat_parser, XML_TRUE);
108546a0 565 if (err != XML_ERROR_NONE)
f34652de 566 internal_error (_("XML_UseForeignDTD failed: %s"),
9b20d036 567 XML_ErrorString (err));
108546a0
DJ
568}
569
e776119f
DJ
570/* Invoke PARSER on BUFFER. BUFFER is the data to parse, which
571 should be NUL-terminated.
572
573 The return value is 0 for success or -1 for error. It may throw,
574 but only if something unexpected goes wrong during parsing; parse
575 errors will be caught, warned about, and reported as failure. */
576
577int
4895cde2 578gdb_xml_parser::parse (const char *buffer)
e776119f
DJ
579{
580 enum XML_Status status;
581 const char *error_string;
582
4895cde2 583 gdb_xml_debug (this, _("Starting:\n%s"), buffer);
de584861 584
4895cde2 585 status = XML_Parse (m_expat_parser, buffer, strlen (buffer), 1);
e776119f 586
4895cde2 587 if (status == XML_STATUS_OK && m_error.reason == 0)
e776119f
DJ
588 return 0;
589
4895cde2
PA
590 if (m_error.reason == RETURN_ERROR
591 && m_error.error == XML_PARSE_ERROR)
e776119f 592 {
4895cde2 593 gdb_assert (m_error.message != NULL);
3d6e9d23 594 error_string = m_error.what ();
e776119f
DJ
595 }
596 else if (status == XML_STATUS_ERROR)
597 {
4895cde2 598 enum XML_Error err = XML_GetErrorCode (m_expat_parser);
a109c7c1 599
e776119f
DJ
600 error_string = XML_ErrorString (err);
601 }
602 else
603 {
4895cde2 604 gdb_assert (m_error.reason < 0);
94aeb44b 605 throw_exception (std::move (m_error));
e776119f
DJ
606 }
607
4895cde2
PA
608 if (m_last_line != 0)
609 warning (_("while parsing %s (at line %d): %s"), m_name,
610 m_last_line, error_string);
e776119f 611 else
4895cde2 612 warning (_("while parsing %s: %s"), m_name, error_string);
e776119f
DJ
613
614 return -1;
fd79ecee
DJ
615}
616
efc0eabd
PA
617int
618gdb_xml_parse_quick (const char *name, const char *dtd_name,
619 const struct gdb_xml_element *elements,
620 const char *document, void *user_data)
621{
010151c9 622 gdb_xml_parser parser (name, elements, user_data);
efc0eabd 623 if (dtd_name != NULL)
4895cde2
PA
624 parser.use_dtd (dtd_name);
625 return parser.parse (document);
efc0eabd
PA
626}
627
fd79ecee
DJ
628/* Parse a field VALSTR that we expect to contain an integer value.
629 The integer is returned in *VALP. The string is parsed with an
630 equivalent to strtoul.
631
632 Returns 0 for success, -1 for error. */
633
634static int
635xml_parse_unsigned_integer (const char *valstr, ULONGEST *valp)
636{
637 const char *endptr;
638 ULONGEST result;
639
640 if (*valstr == '\0')
641 return -1;
642
643 result = strtoulst (valstr, &endptr, 0);
644 if (*endptr != '\0')
645 return -1;
646
647 *valp = result;
648 return 0;
649}
650
e776119f
DJ
651/* Parse an integer string into a ULONGEST and return it, or call
652 gdb_xml_error if it could not be parsed. */
fd79ecee
DJ
653
654ULONGEST
e776119f 655gdb_xml_parse_ulongest (struct gdb_xml_parser *parser, const char *value)
fd79ecee
DJ
656{
657 ULONGEST result;
fd79ecee
DJ
658
659 if (xml_parse_unsigned_integer (value, &result) != 0)
e776119f
DJ
660 gdb_xml_error (parser, _("Can't convert \"%s\" to an integer"), value);
661
fd79ecee
DJ
662 return result;
663}
664
e776119f
DJ
665/* Parse an integer attribute into a ULONGEST. */
666
667void *
668gdb_xml_parse_attr_ulongest (struct gdb_xml_parser *parser,
669 const struct gdb_xml_attribute *attribute,
670 const char *value)
671{
672 ULONGEST result;
673 void *ret;
fd79ecee 674
e776119f
DJ
675 if (xml_parse_unsigned_integer (value, &result) != 0)
676 gdb_xml_error (parser, _("Can't convert %s=\"%s\" to an integer"),
677 attribute->name, value);
fd79ecee 678
8d749320 679 ret = XNEW (ULONGEST);
e776119f
DJ
680 memcpy (ret, &result, sizeof (result));
681 return ret;
682}
683
123dc839
DJ
684/* A handler_data for yes/no boolean values. */
685
686const struct gdb_xml_enum gdb_xml_enums_boolean[] = {
687 { "yes", 1 },
688 { "no", 0 },
689 { NULL, 0 }
690};
691
e776119f
DJ
692/* Map NAME to VALUE. A struct gdb_xml_enum * should be saved as the
693 value of handler_data when using gdb_xml_parse_attr_enum to parse a
694 fixed list of possible strings. The list is terminated by an entry
695 with NAME == NULL. */
696
697void *
698gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser,
699 const struct gdb_xml_attribute *attribute,
700 const char *value)
fd79ecee 701{
19ba03f4
SM
702 const struct gdb_xml_enum *enums
703 = (const struct gdb_xml_enum *) attribute->handler_data;
e776119f 704 void *ret;
fd79ecee 705
19ba03f4
SM
706 for (enums = (const struct gdb_xml_enum *) attribute->handler_data;
707 enums->name != NULL; enums++)
123dc839 708 if (strcasecmp (enums->name, value) == 0)
e776119f
DJ
709 break;
710
711 if (enums->name == NULL)
712 gdb_xml_error (parser, _("Unknown attribute value %s=\"%s\""),
713 attribute->name, value);
714
715 ret = xmalloc (sizeof (enums->value));
716 memcpy (ret, &enums->value, sizeof (enums->value));
717 return ret;
fd79ecee 718}
108546a0
DJ
719\f
720
721/* XInclude processing. This is done as a separate step from actually
722 parsing the document, so that we can produce a single combined XML
723 document - e.g. to hand to a front end or to simplify comparing two
724 documents. We make extensive use of XML_DefaultCurrent, to pass
725 input text directly into the output without reformatting or
726 requoting it.
727
728 We output the DOCTYPE declaration for the first document unchanged,
729 if present, and discard DOCTYPEs from included documents. Only the
730 one we pass through here is used when we feed the result back to
731 expat. The XInclude standard explicitly does not discuss
732 validation of the result; we choose to apply the same DTD applied
733 to the outermost document.
734
735 We can not simply include the external DTD subset in the document
736 as an internal subset, because <!IGNORE> and <!INCLUDE> are valid
737 only in external subsets. But if we do not pass the DTD into the
738 output at all, default values will not be filled in.
739
740 We don't pass through any <?xml> declaration because we generate
741 UTF-8, not whatever the input encoding was. */
742
743struct xinclude_parsing_data
744{
bd8a901f 745 xinclude_parsing_data (std::string &output_,
8400a90d 746 xml_fetch_another fetcher_,
010151c9 747 int include_depth_)
bd8a901f
PA
748 : output (output_),
749 skip_depth (0),
010151c9 750 include_depth (include_depth_),
8400a90d 751 fetcher (fetcher_)
bd8a901f 752 {}
010151c9 753
bd8a901f
PA
754 /* Where the output goes. */
755 std::string &output;
108546a0
DJ
756
757 /* A count indicating whether we are in an element whose
758 children should not be copied to the output, and if so,
759 how deep we are nested. This is used for anything inside
760 an xi:include, and for the DTD. */
761 int skip_depth;
762
763 /* The number of <xi:include> elements currently being processed,
764 to detect loops. */
765 int include_depth;
766
767 /* A function to call to obtain additional features, and its
768 baton. */
769 xml_fetch_another fetcher;
108546a0
DJ
770};
771
772static void
773xinclude_start_include (struct gdb_xml_parser *parser,
774 const struct gdb_xml_element *element,
4d0fdd9b
SM
775 void *user_data,
776 std::vector<gdb_xml_value> &attributes)
108546a0 777{
19ba03f4
SM
778 struct xinclude_parsing_data *data
779 = (struct xinclude_parsing_data *) user_data;
4d0fdd9b 780 char *href = (char *) xml_find_attribute (attributes, "href")->value.get ();
108546a0
DJ
781
782 gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href);
783
784 if (data->include_depth > MAX_XINCLUDE_DEPTH)
785 gdb_xml_error (parser, _("Maximum XInclude depth (%d) exceeded"),
786 MAX_XINCLUDE_DEPTH);
787
8400a90d 788 gdb::optional<gdb::char_vector> text = data->fetcher (href);
9018be22 789 if (!text)
108546a0 790 gdb_xml_error (parser, _("Could not load XML document \"%s\""), href);
108546a0 791
4895cde2 792 if (!xml_process_xincludes (data->output, parser->name (),
9018be22 793 text->data (), data->fetcher,
bd8a901f 794 data->include_depth + 1))
108546a0
DJ
795 gdb_xml_error (parser, _("Parsing \"%s\" failed"), href);
796
108546a0
DJ
797 data->skip_depth++;
798}
799
800static void
801xinclude_end_include (struct gdb_xml_parser *parser,
802 const struct gdb_xml_element *element,
803 void *user_data, const char *body_text)
804{
19ba03f4
SM
805 struct xinclude_parsing_data *data
806 = (struct xinclude_parsing_data *) user_data;
108546a0
DJ
807
808 data->skip_depth--;
809}
810
811static void XMLCALL
812xml_xinclude_default (void *data_, const XML_Char *s, int len)
813{
19ba03f4 814 struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_;
4895cde2 815 xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data ();
108546a0
DJ
816
817 /* If we are inside of e.g. xi:include or the DTD, don't save this
818 string. */
819 if (data->skip_depth)
820 return;
821
822 /* Otherwise just add it to the end of the document we're building
823 up. */
bd8a901f 824 data->output.append (s, len);
108546a0
DJ
825}
826
827static void XMLCALL
828xml_xinclude_start_doctype (void *data_, const XML_Char *doctypeName,
829 const XML_Char *sysid, const XML_Char *pubid,
830 int has_internal_subset)
831{
19ba03f4 832 struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_;
4895cde2 833 xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data ();
108546a0
DJ
834
835 /* Don't print out the doctype, or the contents of the DTD internal
836 subset, if any. */
837 data->skip_depth++;
838}
839
840static void XMLCALL
841xml_xinclude_end_doctype (void *data_)
842{
19ba03f4 843 struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_;
4895cde2 844 xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data ();
108546a0
DJ
845
846 data->skip_depth--;
847}
848
849static void XMLCALL
850xml_xinclude_xml_decl (void *data_, const XML_Char *version,
851 const XML_Char *encoding, int standalone)
852{
853 /* Do nothing - this function prevents the default handler from
854 being called, thus suppressing the XML declaration from the
855 output. */
856}
857
108546a0
DJ
858const struct gdb_xml_attribute xinclude_attributes[] = {
859 { "href", GDB_XML_AF_NONE, NULL, NULL },
860 { NULL, GDB_XML_AF_NONE, NULL, NULL }
861};
862
863const struct gdb_xml_element xinclude_elements[] = {
864 { "http://www.w3.org/2001/XInclude!include", xinclude_attributes, NULL,
865 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
866 xinclude_start_include, xinclude_end_include },
867 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
868};
869
870/* The main entry point for <xi:include> processing. */
871
bd8a901f
PA
872bool
873xml_process_xincludes (std::string &result,
874 const char *name, const char *text,
8400a90d 875 xml_fetch_another fetcher, int depth)
108546a0 876{
8400a90d 877 xinclude_parsing_data data (result, fetcher, depth);
108546a0 878
010151c9 879 gdb_xml_parser parser (name, xinclude_elements, &data);
4895cde2 880 parser.set_is_xinclude (true);
108546a0 881
4895cde2
PA
882 XML_SetCharacterDataHandler (parser.expat_parser (), NULL);
883 XML_SetDefaultHandler (parser.expat_parser (), xml_xinclude_default);
108546a0
DJ
884
885 /* Always discard the XML version declarations; the only important
886 thing this provides is encoding, and our result will have been
887 converted to UTF-8. */
4895cde2 888 XML_SetXmlDeclHandler (parser.expat_parser (), xml_xinclude_xml_decl);
108546a0
DJ
889
890 if (depth > 0)
891 /* Discard the doctype for included documents. */
4895cde2 892 XML_SetDoctypeDeclHandler (parser.expat_parser (),
108546a0
DJ
893 xml_xinclude_start_doctype,
894 xml_xinclude_end_doctype);
895
4895cde2 896 parser.use_dtd ("xinclude.dtd");
108546a0 897
4895cde2 898 if (parser.parse (text) == 0)
108546a0 899 {
108546a0 900 if (depth == 0)
010151c9 901 gdb_xml_debug (&parser, _("XInclude processing succeeded."));
bd8a901f 902 return true;
108546a0 903 }
108546a0 904
bd8a901f 905 return false;
108546a0 906}
05a4558a 907#endif /* HAVE_LIBEXPAT */
108546a0
DJ
908\f
909
910/* Return an XML document which was compiled into GDB, from
911 the given FILENAME, or NULL if the file was not compiled in. */
912
913const char *
914fetch_xml_builtin (const char *filename)
915{
fec4e896 916 const char *const (*p)[2];
108546a0
DJ
917
918 for (p = xml_builtin; (*p)[0]; p++)
919 if (strcmp ((*p)[0], filename) == 0)
920 return (*p)[1];
921
922 return NULL;
923}
fd79ecee 924
05a4558a
DJ
925/* A to_xfer_partial helper function which reads XML files which were
926 compiled into GDB. The target may call this function from its own
927 to_xfer_partial handler, after converting object and annex to the
928 appropriate filename. */
929
930LONGEST
931xml_builtin_xfer_partial (const char *filename,
932 gdb_byte *readbuf, const gdb_byte *writebuf,
933 ULONGEST offset, LONGEST len)
934{
935 const char *buf;
936 LONGEST len_avail;
937
938 gdb_assert (readbuf != NULL && writebuf == NULL);
939 gdb_assert (filename != NULL);
940
941 buf = fetch_xml_builtin (filename);
942 if (buf == NULL)
943 return -1;
944
945 len_avail = strlen (buf);
946 if (offset >= len_avail)
947 return 0;
948
949 if (len > len_avail - offset)
950 len = len_avail - offset;
951 memcpy (readbuf, buf + offset, len);
952 return len;
953}
954\f
fd79ecee
DJ
955
956static void
e776119f
DJ
957show_debug_xml (struct ui_file *file, int from_tty,
958 struct cmd_list_element *c, const char *value)
fd79ecee 959{
6cb06a8c 960 gdb_printf (file, _("XML debugging is %s.\n"), value);
fd79ecee
DJ
961}
962
9018be22 963gdb::optional<gdb::char_vector>
8400a90d 964xml_fetch_content_from_file (const char *filename, const char *dirname)
a96d9b2e 965{
d419f42d 966 gdb_file_up file;
a96d9b2e 967
8400a90d 968 if (dirname != nullptr && *dirname != '\0')
a96d9b2e 969 {
33f4dd48
SM
970 gdb::unique_xmalloc_ptr<char> fullname
971 (concat (dirname, "/", filename, (char *) NULL));
a109c7c1 972
33f4dd48 973 file = gdb_fopen_cloexec (fullname.get (), FOPEN_RB);
a96d9b2e
SDJ
974 }
975 else
f69656d0 976 file = gdb_fopen_cloexec (filename, FOPEN_RB);
a96d9b2e
SDJ
977
978 if (file == NULL)
9018be22 979 return {};
a96d9b2e 980
2edf834e 981 /* Read in the whole file. */
a96d9b2e 982
2edf834e 983 size_t len;
a96d9b2e 984
2edf834e
PA
985 if (fseek (file.get (), 0, SEEK_END) == -1)
986 perror_with_name (_("seek to end of file"));
987 len = ftell (file.get ());
988 rewind (file.get ());
a96d9b2e 989
9018be22 990 gdb::char_vector text (len + 1);
a96d9b2e 991
9018be22 992 if (fread (text.data (), 1, len, file.get ()) != len
63929e84 993 || ferror (file.get ()))
2edf834e
PA
994 {
995 warning (_("Read error from \"%s\""), filename);
9018be22 996 return {};
a96d9b2e
SDJ
997 }
998
9018be22 999 text.back () = '\0';
a96d9b2e
SDJ
1000 return text;
1001}
1002
6c265988
SM
1003void _initialize_xml_support ();
1004void _initialize_xml_support ();
fd79ecee 1005void
6c265988 1006_initialize_xml_support ()
fd79ecee 1007{
e776119f
DJ
1008 add_setshow_boolean_cmd ("xml", class_maintenance, &debug_xml,
1009 _("Set XML parser debugging."),
1010 _("Show XML parser debugging."),
1011 _("When set, debugging messages for XML parsers "
1012 "are displayed."),
1013 NULL, show_debug_xml,
1014 &setdebuglist, &showdebuglist);
fd79ecee 1015}