From: Daniel Jacobowitz Date: Tue, 9 Jan 2007 22:55:10 +0000 (+0000) Subject: XML feature description support. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=23181151a2399f4ecbc272cda73172a078d1b435;p=binutils-gdb.git XML feature description support. * NEWS: Mention target descriptions, "set tdesc filename", "unset tdesc filename", "show tdesc filename", and qXfer:features:read. * arch-utils.c (choose_architecture_for_target): New function. (gdbarch_info_fill): Call it. * target-descriptions.c (struct property): Make members non-const. (struct target_desc): Add arch member. (target_description_filename): New variable. (target_find_description): Try via XML first. (tdesc_architecture): New. (free_target_description, make_cleanup_free_target_description): New. (set_tdesc_property): Call xstrdup. (set_tdesc_architecture, tdesc_set_cmdlist, tdesc_show_cmdlist) (tdesc_unset_cmdlist, unset_tdesc_cmd, unset_tdesc_filename_cmd) (set_tdesc_cmd, show_tdesc_cmd, set_tdesc_filename_cmd) (show_tdesc_filename_cmd, _initialize_target_descriptions): New. * target-descriptions.h (tdesc_architecture) (make_cleanup_free_target_description, set_tdesc_architecture): New prototypes. * Makefile.in (SFILES): Add xml-tdesc.c. (COMMON_OBS): Add xml-tdesc.o. (target-descriptions.o): Update. (xml-tdesc.o): New rule. * xml-tdesc.c, xml-tdesc.h: New files. * remote.c (PACKET_qXfer_features): New enum. (remote_protocol_features): Add qXfer:features:read. (remote_xfer_partial): Handle TARGET_OBJECT_AVAILABLE_FEATURES. (_initialize_remote): Register qXfer:features:read. * target.h (enum target_object): Add TARGET_OBJECT_AVAILABLE_FEATURES. * features/gdb-target.dtd: New file. * linux-i386-low.c (the_low_target): Set arch_string. * linux-x86-64-low.c (the_low_target): Likewise. * linux-low.c (linux_arch_string): New. (linux_target_ops): Add it. * linux-low.h (struct linux_target_ops): Add arch_string. * server.c (write_qxfer_response): Use const void * for DATA. (get_features_xml): New. (handle_query): Handle qXfer:features:read. Report it for qSupported. * target.h (struct target_ops): Add arch_string method. * gdb.texinfo (Target Descriptions): New section. (General Query Packets): Add QPassSignals anchor. Mention qXfer:features:read under qSupported. Expand mentions of qXfer:memory-map:read and QPassSignals. Document qXfer:features:read. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3060ed7b1df..3c2b27aa03d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,36 @@ +2007-01-09 Daniel Jacobowitz + + * NEWS: Mention target descriptions, "set tdesc filename", + "unset tdesc filename", "show tdesc filename", and + qXfer:features:read. + * arch-utils.c (choose_architecture_for_target): New function. + (gdbarch_info_fill): Call it. + * target-descriptions.c (struct property): Make members non-const. + (struct target_desc): Add arch member. + (target_description_filename): New variable. + (target_find_description): Try via XML first. + (tdesc_architecture): New. + (free_target_description, make_cleanup_free_target_description): New. + (set_tdesc_property): Call xstrdup. + (set_tdesc_architecture, tdesc_set_cmdlist, tdesc_show_cmdlist) + (tdesc_unset_cmdlist, unset_tdesc_cmd, unset_tdesc_filename_cmd) + (set_tdesc_cmd, show_tdesc_cmd, set_tdesc_filename_cmd) + (show_tdesc_filename_cmd, _initialize_target_descriptions): New. + * target-descriptions.h (tdesc_architecture) + (make_cleanup_free_target_description, set_tdesc_architecture): New + prototypes. + * Makefile.in (SFILES): Add xml-tdesc.c. + (COMMON_OBS): Add xml-tdesc.o. + (target-descriptions.o): Update. + (xml-tdesc.o): New rule. + * xml-tdesc.c, xml-tdesc.h: New files. + * remote.c (PACKET_qXfer_features): New enum. + (remote_protocol_features): Add qXfer:features:read. + (remote_xfer_partial): Handle TARGET_OBJECT_AVAILABLE_FEATURES. + (_initialize_remote): Register qXfer:features:read. + * target.h (enum target_object): Add TARGET_OBJECT_AVAILABLE_FEATURES. + * features/gdb-target.dtd: New file. + 2007-01-09 Daniel Jacobowitz * copyright.sh: Clarify error. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 1de5f4c26fd..9567fac4580 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -563,7 +563,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \ user-regs.c \ valarith.c valops.c valprint.c value.c varobj.c vec.c \ wrapper.c \ - xml-support.c + xml-tdesc.c xml-support.c LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c @@ -972,7 +972,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 + target-descriptions.o target-memory.o xml-tdesc.o TSOBS = inflow.o @@ -2776,7 +2776,8 @@ target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \ $(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \ $(exceptions_h) $(target_descriptions_h) target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \ - $(target_h) $(target_descriptions_h) $(vec_h) $(gdb_assert_h) + $(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \ + $(gdbcmd_h) $(gdb_assert_h) target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \ $(memory_map_h) $(gdb_assert_h) thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \ @@ -2874,6 +2875,8 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \ $(complaints_h) $(gdb_stabs_h) $(aout_stab_gnu_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-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) \ diff --git a/gdb/NEWS b/gdb/NEWS index 708df779972..a40e94f32c7 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -11,6 +11,10 @@ frequency signals (e.g. SIGALRM) via the QPassSignals packet. * Support for C++ member pointers has been improved. +* GDB now understands XML target descriptions, which specify the +target's overall architecture. GDB can read a description from +a local file or over the remote serial protocol. + * New commands set mem inaccessible-by-default @@ -47,6 +51,12 @@ show sysroot OpenBSD/sh sh*-*openbsd* +set tdesc filename +unset tdesc filename +show tdesc filename + Use the specified local file as an XML target description, and do + not query the target for its built-in description. + * New targets OpenBSD/sh sh*-*-openbsd* @@ -58,6 +68,9 @@ QPassSignals: Ignore the specified signals; pass them directly to the debugged program without stopping other threads or reporting them to GDB. +qXfer:features:read: + Read an XML target description from the target, which describes its + features. *** Changes in GDB 6.6 diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 78768a61a91..36359553441 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -409,6 +409,75 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) show_endian (gdb_stdout, from_tty, NULL, NULL); } +/* Given SELECTED, a currently selected BFD architecture, and + FROM_TARGET, a BFD architecture reported by the target description, + return what architecture to use. Either may be NULL; if both are + specified, we use the more specific. If the two are obviously + incompatible, warn the user. */ + +static const struct bfd_arch_info * +choose_architecture_for_target (const struct bfd_arch_info *selected, + const struct bfd_arch_info *from_target) +{ + const struct bfd_arch_info *compat1, *compat2; + + if (selected == NULL) + return from_target; + + if (from_target == NULL) + return selected; + + /* struct bfd_arch_info objects are singletons: that is, there's + supposed to be exactly one instance for a given machine. So you + can tell whether two are equivalent by comparing pointers. */ + if (from_target == selected) + return selected; + + /* BFD's 'A->compatible (A, B)' functions return zero if A and B are + incompatible. But if they are compatible, it returns the 'more + featureful' of the two arches. That is, if A can run code + written for B, but B can't run code written for A, then it'll + return A. + + Some targets (e.g. MIPS as of 2006-12-04) don't fully + implement this, instead always returning NULL or the first + argument. We detect that case by checking both directions. */ + + compat1 = selected->compatible (selected, from_target); + compat2 = from_target->compatible (from_target, selected); + + if (compat1 == NULL && compat2 == NULL) + { + warning (_("Selected architecture %s is not compatible " + "with reported target architecture %s"), + selected->printable_name, from_target->printable_name); + return selected; + } + + if (compat1 == NULL) + return compat2; + if (compat2 == NULL) + return compat1; + if (compat1 == compat2) + return compat1; + + /* If the two didn't match, but one of them was a default architecture, + assume the more specific one is correct. This handles the case + where an executable or target description just says "mips", but + the other knows which MIPS variant. */ + if (compat1->the_default) + return compat2; + if (compat2->the_default) + return compat1; + + /* We have no idea which one is better. This is a bug, but not + a critical problem; warn the user. */ + warning (_("Selected architecture %s is ambiguous with " + "reported target architecture %s"), + selected->printable_name, from_target->printable_name); + return selected; +} + /* Functions to manipulate the architecture of the target */ enum set_arch { set_arch_auto, set_arch_manual }; @@ -703,6 +772,10 @@ gdbarch_info_fill (struct gdbarch_info *info) && bfd_get_arch (info->abfd) != bfd_arch_unknown && bfd_get_arch (info->abfd) != bfd_arch_obscure) info->bfd_arch_info = bfd_get_arch_info (info->abfd); + /* From the target. */ + if (info->target_desc != NULL) + info->bfd_arch_info = choose_architecture_for_target + (info->bfd_arch_info, tdesc_architecture (info->target_desc)); /* From the default. */ if (info->bfd_arch_info == NULL) info->bfd_arch_info = default_bfd_arch; diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index a20f9aaffb9..d1b27da2733 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,11 @@ +2007-01-09 Daniel Jacobowitz + + * gdb.texinfo (Target Descriptions): New section. + (General Query Packets): Add QPassSignals anchor. Mention + qXfer:features:read under qSupported. Expand mentions of + qXfer:memory-map:read and QPassSignals. Document + qXfer:features:read. + 2007-01-08 Daniel Jacobowitz * gdb.texinfo (Commands to specify files): Describe diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b3167b1eb2b..446e061612b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -159,6 +159,8 @@ Copyright (C) 1988-2006 Free Software Foundation, Inc. * Maintenance Commands:: Maintenance Commands * Remote Protocol:: GDB Remote Serial Protocol * Agent Expressions:: The GDB Agent Expression Mechanism +* Target Descriptions:: How targets can describe themselves to + @value{GDBN} * Copying:: GNU General Public License says how you can copy and share GDB * GNU Free Documentation License:: The license for this documentation @@ -23702,6 +23704,7 @@ Reply: see @code{remote.c:remote_unpack_thread_info_response()}. @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} @cindex pass signals to inferior, remote request @cindex @samp{QPassSignals} packet +@anchor{QPassSignals} Each listed @var{signal} should be passed directly to the inferior process. Signals are numbered identically to continue packets and stop replies (@pxref{Stop Reply Packets}). Each @var{signal} list item should be @@ -23868,6 +23871,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{qXfer:features:read} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{qXfer:memory-map:read} @tab No @tab @samp{-} @@ -23898,6 +23906,18 @@ byte in its buffer for the NUL. If this stub feature is not supported, The remote stub understands the @samp{qXfer:auxv:read} packet (@pxref{qXfer auxiliary vector read}). +@item qXfer:features:read +The remote stub understands the @samp{qXfer:features:read} packet +(@pxref{qXfer target description read}). + +@item qXfer:memory-map:read +The remote stub understands the @samp{qXfer:memory-map:read} packet +(@pxref{qXfer memory map read}). + +@item QPassSignals +The remote stub understands the @samp{QPassSignals} packet +(@pxref{QPassSignals}). + @end table @item qSymbol:: @@ -23994,9 +24014,16 @@ auxiliary vector}. Note @var{annex} must be empty. This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). -@end table -@table @samp +@item qXfer:features:read:@var{annex}:@var{offset},@var{length} +@anchor{qXfer target description read} +Access the @dfn{target description}. @xref{Target Descriptions}. The +annex specifies which XML document to access. The main description is +always loaded from the @samp{target.xml} annex. + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item qXfer:memory-map:read::@var{offset},@var{length} @anchor{qXfer memory map read} Access the target's @dfn{memory-map}. @xref{Memory map format}. The @@ -25571,6 +25598,130 @@ The formal DTD for memory map format is given below: @include agentexpr.texi +@node Target Descriptions +@appendix Target Descriptions +@cindex target descriptions + +@strong{Warning:} target descriptions are still under active development, +and the contents and format may change between @value{GDBN} releases. +The format is expected to stabilize in the future. + +One of the challenges of using @value{GDBN} to debug embedded systems +is that there are so many minor variants of each processor +architecture in use. It is common practice for vendors to start with +a standard processor core --- ARM, PowerPC, or MIPS, for example --- +and then make changes to adapt it to a particular market niche. Some +architectures have hundreds of variants, available from dozens of +vendors. This leads to a number of problems: + +@itemize @bullet +@item +With so many different customized processors, it is difficult for +the @value{GDBN} maintainers to keep up with the changes. +@item +Since individual variants may have short lifetimes or limited +audiences, it may not be worthwhile to carry information about every +variant in the @value{GDBN} source tree. +@item +When @value{GDBN} does support the architecture of the embedded system +at hand, the task of finding the correct architecture name to give the +@command{set architecture} command can be error-prone. +@end itemize + +To address these problems, the @value{GDBN} remote protocol allows a +target system to not only identify itself to @value{GDBN}, but to +actually describe its own features. This lets @value{GDBN} support +processor variants it has never seen before --- to the extent that the +descriptions are accurate, and that @value{GDBN} understands them. + +@menu +* Retrieving Descriptions:: How descriptions are fetched from a target. +* Target Description Format:: The contents of a target description. +@end menu + +@node Retrieving Descriptions +@section Retrieving Descriptions + +Target descriptions can be read from the target automatically, or +specified by the user manually. The default behavior is to read the +description from the target. @value{GDBN} retrieves it via the remote +protocol using @samp{qXfer} requests (@pxref{General Query Packets, +qXfer}). The @var{annex} in the @samp{qXfer} packet will be +@samp{target.xml}. The contents of the @samp{target.xml} annex are an +XML document, of the form described in @ref{Target Description +Format}. + +Alternatively, you can specify a file to read for the target description. +If a file is set, the target will not be queried. The commands to +specify a file are: + +@table @code +@cindex set tdesc filename +@item set tdesc filename @var{path} +Read the target description from @var{path}. + +@cindex unset tdesc filename +@item unset tdesc filename +Do not read the XML target description from a file. @value{GDBN} +will use the description supplied by the current target. + +@cindex show tdesc filename +@item show tdesc filename +Show the filename to read for a target description, if any. +@end table + + +@node Target Description Format +@section Target Description Format +@cindex target descriptions, XML format + +A target description annex is an @uref{http://www.w3.org/XML/, XML} +document which complies with the Document Type Definition provided in +the @value{GDBN} sources in @file{gdb/features/gdb-target.dtd}. This +means you can use generally available tools like @command{xmllint} to +check that your feature descriptions are well-formed and valid. +However, to help people unfamiliar with XML write descriptions for +their targets, we also describe the grammar here. + +At the moment, target descriptions can only provide minimal information +about the architecture of the remote target. @value{GDBN} can use this +information to autoconfigure, or to warn you if you connect to an +unsupported target. + +Here is a simple target description: + +@example + + i386:x86-64 + +@end example + +@noindent +This minimal description only says that the target uses +the x86-64 architecture. + +A target description has the overall form: + +@example + + + + @var{arch name} + +@end example + +@noindent +The description is generally insensitive to whitespace and line +breaks, under the usual common-sense rules. The XML version +declaration and document type declaration can generally be omitted +(@value{GDBN} does not require them), but specifying them may be +useful for XML validation tools. + +The content of the @samp{} element is an architecture +name, from the same selection accepted by @code{set architecture} +(@pxref{Targets, ,Specifying a Debugging Target}). + + @include gpl.texi @raisesections diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 2035473d5d7..8336ecabaf8 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,15 @@ +2007-01-09 Daniel Jacobowitz + + * linux-i386-low.c (the_low_target): Set arch_string. + * linux-x86-64-low.c (the_low_target): Likewise. + * linux-low.c (linux_arch_string): New. + (linux_target_ops): Add it. + * linux-low.h (struct linux_target_ops): Add arch_string. + * server.c (write_qxfer_response): Use const void * for DATA. + (get_features_xml): New. + (handle_query): Handle qXfer:features:read. Report it for qSupported. + * target.h (struct target_ops): Add arch_string method. + 2007-01-03 Denis Pilat Daniel Jacobowitz diff --git a/gdb/gdbserver/linux-i386-low.c b/gdb/gdbserver/linux-i386-low.c index 4710773b77e..10c0ef0f458 100644 --- a/gdb/gdbserver/linux-i386-low.c +++ b/gdb/gdbserver/linux-i386-low.c @@ -198,4 +198,10 @@ struct linux_target_ops the_low_target = { NULL, 1, i386_breakpoint_at, + NULL, + NULL, + NULL, + NULL, + 0, + "i386" }; diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index eb8ef4835bb..1d495936305 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -1641,6 +1641,12 @@ linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p) } #endif +static const char * +linux_arch_string (void) +{ + return the_low_target.arch_string; +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -1670,6 +1676,7 @@ static struct target_ops linux_target_ops = { #else NULL, #endif + linux_arch_string, }; static void diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index aa0102b7327..aa3bfe1268e 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -71,6 +71,10 @@ struct linux_target_ops /* Whether to left-pad registers for PEEKUSR/POKEUSR if they are smaller than an xfer unit. */ int left_pad_xfer; + + /* What string to report to GDB when it asks for the architecture, + or NULL not to answer. */ + const char *arch_string; }; extern struct linux_target_ops the_low_target; diff --git a/gdb/gdbserver/linux-x86-64-low.c b/gdb/gdbserver/linux-x86-64-low.c index 81c92feeb53..5951104d421 100644 --- a/gdb/gdbserver/linux-x86-64-low.c +++ b/gdb/gdbserver/linux-x86-64-low.c @@ -172,4 +172,10 @@ struct linux_target_ops the_low_target = { NULL, 1, x86_64_breakpoint_at, + NULL, + NULL, + NULL, + NULL, + 0, + "i386:x86-64", }; diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 1f78cce6920..20d47c92716 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -145,7 +145,7 @@ decode_xfer_read (char *buf, char **annex, CORE_ADDR *ofs, unsigned int *len) to as much of DATA/LEN as we could fit. IS_MORE controls the first character of the response. */ static int -write_qxfer_response (char *buf, unsigned char *data, int len, int is_more) +write_qxfer_response (char *buf, const void *data, int len, int is_more) { int out_len; @@ -192,6 +192,31 @@ handle_general_set (char *own_buf) own_buf[0] = 0; } +static const char * +get_features_xml (void) +{ + static int features_supported = -1; + static char *document; + + if (features_supported == -1) + { + const char *arch = (*the_target->arch_string) (); + + if (arch == NULL) + features_supported = 0; + else + { + features_supported = 1; + document = malloc (64 + strlen (arch)); + snprintf (document, 64 + strlen (arch), + "%s", + arch); + } + } + + return document; +} + /* Handle all of the extended 'q' packets. */ void handle_query (char *own_buf, int *new_packet_len_p) @@ -279,6 +304,45 @@ handle_query (char *own_buf, int *new_packet_len_p) return; } + if (strncmp ("qXfer:features:read:", own_buf, 20) == 0) + { + CORE_ADDR ofs; + unsigned int len, total_len; + const char *document; + char *annex; + + document = get_features_xml (); + if (document == NULL) + { + own_buf[0] = '\0'; + return; + } + + /* Reject any annex other than target.xml; grab the offset and + length. */ + if (decode_xfer_read (own_buf + 20, &annex, &ofs, &len) < 0 + || strcmp (annex, "target.xml") != 0) + { + strcpy (own_buf, "E00"); + return; + } + + total_len = strlen (document); + if (len > PBUFSIZ - 2) + len = PBUFSIZ - 2; + + if (ofs > total_len) + write_enn (own_buf); + else if (len < total_len - ofs) + *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, + len, 1); + else + *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, + total_len - ofs, 0); + + return; + } + /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) @@ -288,6 +352,9 @@ handle_query (char *own_buf, int *new_packet_len_p) if (the_target->read_auxv != NULL) strcat (own_buf, ";qXfer:auxv:read+"); + if (get_features_xml () != NULL) + strcat (own_buf, ";qXfer:features:read+"); + return; } diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 17137dcb23e..d6e2655bf94 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -171,6 +171,10 @@ struct target_ops int (*get_tls_address) (struct thread_info *thread, CORE_ADDR offset, CORE_ADDR load_module, CORE_ADDR *address); + + /* Return a string identifying the current architecture, or NULL if + this operation is not supported. */ + const char *(*arch_string) (void); }; extern struct target_ops *the_target; diff --git a/gdb/remote.c b/gdb/remote.c index c229bffab22..48be84479ec 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -893,6 +893,7 @@ enum { PACKET_Z3, PACKET_Z4, PACKET_qXfer_auxv, + PACKET_qXfer_features, PACKET_qXfer_memory_map, PACKET_qGetTLSAddr, PACKET_qSupported, @@ -2294,6 +2295,8 @@ static struct protocol_feature remote_protocol_features[] = { { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 }, { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_auxv }, + { "qXfer:features:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_features }, { "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_memory_map }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, @@ -5716,6 +5719,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object, return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len, &remote_protocol_packets[PACKET_qXfer_auxv]); + case TARGET_OBJECT_AVAILABLE_FEATURES: + return remote_read_qxfer + (ops, "features", annex, readbuf, offset, len, + &remote_protocol_packets[PACKET_qXfer_features]); + case TARGET_OBJECT_MEMORY_MAP: gdb_assert (annex == NULL); return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len, @@ -6589,6 +6597,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv], "qXfer:auxv:read", "read-aux-vector", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_features], + "qXfer:features:read", "target-features", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map], "qXfer:memory-map:read", "memory-map", 0); diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 9699b7d47c9..1100f5ebaf3 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -23,9 +23,11 @@ #include "defs.h" #include "arch-utils.h" +#include "gdbcmd.h" #include "target.h" #include "target-descriptions.h" #include "vec.h" +#include "xml-tdesc.h" #include "gdb_assert.h" @@ -33,13 +35,16 @@ typedef struct property { - const char *key; - const char *value; + char *key; + char *value; } property_s; DEF_VEC_O(property_s); struct target_desc { + /* The architecture reported by the target, if any. */ + const struct bfd_arch_info *arch; + /* Any architecture-specific properties specified by the target. */ VEC(property_s) *properties; }; @@ -61,6 +66,12 @@ static int target_desc_fetched; static const struct target_desc *current_target_desc; +/* Other global variables. */ + +/* The filename to read a target description from. */ + +static char *target_description_filename; + /* Fetch the current target's description, and switch the current architecture to one which incorporates that description. */ @@ -79,7 +90,22 @@ target_find_description (void) disconnected from the previous target. */ gdb_assert (gdbarch_target_desc (current_gdbarch) == NULL); - current_target_desc = target_read_description (¤t_target); + /* First try to fetch an XML description from the user-specified + file. */ + current_target_desc = NULL; + if (target_description_filename != NULL + && *target_description_filename != '\0') + current_target_desc + = file_read_description_xml (target_description_filename); + + /* Next try to read the description from the current target using + target objects. */ + if (current_target_desc == NULL) + current_target_desc = target_read_description_xml (¤t_target); + + /* If that failed try a target-specific hook. */ + if (current_target_desc == NULL) + current_target_desc = target_read_description (¤t_target); /* If a non-NULL description was returned, then update the current architecture. */ @@ -130,6 +156,9 @@ target_current_description (void) return NULL; } + + +/* Direct accessors for feature sets. */ /* Return the string value of a property named KEY, or NULL if the property was not specified. */ @@ -148,6 +177,16 @@ tdesc_property (const struct target_desc *target_desc, const char *key) return NULL; } +/* Return the BFD architecture associated with this target + description, or NULL if no architecture was specified. */ + +const struct bfd_arch_info * +tdesc_architecture (const struct target_desc *target_desc) +{ + return target_desc->arch; +} + + /* Methods for constructing a target description. */ struct target_desc * @@ -156,6 +195,31 @@ allocate_target_description (void) return XZALLOC (struct target_desc); } +static void +free_target_description (void *arg) +{ + struct target_desc *target_desc = arg; + struct property *prop; + int ix; + + for (ix = 0; + VEC_iterate (property_s, target_desc->properties, ix, prop); + ix++) + { + xfree (prop->key); + xfree (prop->value); + } + VEC_free (property_s, target_desc->properties); + + xfree (target_desc); +} + +struct cleanup * +make_cleanup_free_target_description (struct target_desc *target_desc) +{ + return make_cleanup (free_target_description, target_desc); +} + void set_tdesc_property (struct target_desc *target_desc, const char *key, const char *value) @@ -171,7 +235,102 @@ set_tdesc_property (struct target_desc *target_desc, internal_error (__FILE__, __LINE__, _("Attempted to add duplicate property \"%s\""), key); - new_prop.key = key; - new_prop.value = value; + new_prop.key = xstrdup (key); + new_prop.value = xstrdup (value); VEC_safe_push (property_s, target_desc->properties, &new_prop); } + +void +set_tdesc_architecture (struct target_desc *target_desc, + const struct bfd_arch_info *arch) +{ + target_desc->arch = arch; +} + + +static struct cmd_list_element *tdesc_set_cmdlist, *tdesc_show_cmdlist; +static struct cmd_list_element *tdesc_unset_cmdlist; + +/* Helper functions for the CLI commands. */ + +static void +set_tdesc_cmd (char *args, int from_tty) +{ + help_list (tdesc_set_cmdlist, "set tdesc ", -1, gdb_stdout); +} + +static void +show_tdesc_cmd (char *args, int from_tty) +{ + cmd_show_list (tdesc_show_cmdlist, from_tty, ""); +} + +static void +unset_tdesc_cmd (char *args, int from_tty) +{ + help_list (tdesc_unset_cmdlist, "unset tdesc ", -1, gdb_stdout); +} + +static void +set_tdesc_filename_cmd (char *args, int from_tty, + struct cmd_list_element *c) +{ + target_clear_description (); + target_find_description (); +} + +static void +show_tdesc_filename_cmd (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + if (value != NULL && *value != '\0') + printf_filtered (_("\ +The target description will be read from \"%s\".\n"), + value); + else + printf_filtered (_("\ +The target description will be read from the target.\n")); +} + +static void +unset_tdesc_filename_cmd (char *args, int from_tty) +{ + xfree (target_description_filename); + target_description_filename = NULL; + target_clear_description (); + target_find_description (); +} + +void +_initialize_target_descriptions (void) +{ + add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\ +Set target description specific variables."), + &tdesc_set_cmdlist, "set tdesc ", + 0 /* allow-unknown */, &setlist); + add_prefix_cmd ("tdesc", class_maintenance, show_tdesc_cmd, _("\ +Show target description specific variables."), + &tdesc_show_cmdlist, "show tdesc ", + 0 /* allow-unknown */, &showlist); + add_prefix_cmd ("tdesc", class_maintenance, unset_tdesc_cmd, _("\ +Unset target description specific variables."), + &tdesc_unset_cmdlist, "unset tdesc ", + 0 /* allow-unknown */, &unsetlist); + + add_setshow_filename_cmd ("filename", class_obscure, + &target_description_filename, + _("\ +Set the file to read for an XML target description"), _("\ +Show the file to read for an XML target description"), _("\ +When set, GDB will read the target description from a local\n\ +file instead of querying the remote target."), + set_tdesc_filename_cmd, + show_tdesc_filename_cmd, + &tdesc_set_cmdlist, &tdesc_show_cmdlist); + + add_cmd ("filename", class_obscure, unset_tdesc_filename_cmd, _("\ +Unset the file to read for an XML target description. When unset,\n\ +GDB will read the description from the target."), + &tdesc_unset_cmdlist); +} diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h index cca90b155c2..f45e53be23c 100644 --- a/gdb/target-descriptions.h +++ b/gdb/target-descriptions.h @@ -44,6 +44,12 @@ const struct target_desc *target_current_description (void); /* Accessors for target descriptions. */ +/* Return the BFD architecture associated with this target + description, or NULL if no architecture was specified. */ + +const struct bfd_arch_info *tdesc_architecture + (const struct target_desc *); + /* Return the string value of a property named KEY, or NULL if the property was not specified. */ @@ -53,6 +59,9 @@ const char *tdesc_property (const struct target_desc *, /* Methods for constructing a target description. */ struct target_desc *allocate_target_description (void); +struct cleanup *make_cleanup_free_target_description (struct target_desc *); +void set_tdesc_architecture (struct target_desc *, + const struct bfd_arch_info *); void set_tdesc_property (struct target_desc *, const char *key, const char *value); diff --git a/gdb/target.h b/gdb/target.h index c8e2cc637c4..7a5f084888b 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -206,8 +206,10 @@ enum target_object a previously erased flash memory. Using it without erasing flash can have unexpected results. Addresses are physical address on target, and not relative to flash start. */ - TARGET_OBJECT_FLASH - + TARGET_OBJECT_FLASH, + /* Available target-specific features, e.g. registers and coprocessors. + See "target-descriptions.c". ANNEX should never be empty. */ + TARGET_OBJECT_AVAILABLE_FEATURES /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */ }; diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c new file mode 100644 index 00000000000..f47e3687b81 --- /dev/null +++ b/gdb/xml-tdesc.c @@ -0,0 +1,233 @@ +/* XML target description support for GDB. + + Copyright (C) 2006 + Free Software Foundation, Inc. + + Contributed by CodeSourcery. + + 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. */ + +#include "defs.h" +#include "target.h" +#include "target-descriptions.h" +#include "xml-support.h" +#include "xml-tdesc.h" + +#include "gdb_assert.h" + +#if !defined(HAVE_LIBEXPAT) + +/* Parse DOCUMENT into a target description. Or don't, since we don't have + an XML parser. */ + +static struct target_desc * +tdesc_parse_xml (const char *document) +{ + static int have_warned; + + if (!have_warned) + { + have_warned = 1; + warning (_("Can not parse XML target description; XML support was " + "disabled at compile time")); + } + + return NULL; +} + +#else /* HAVE_LIBEXPAT */ + +/* Callback data for target description parsing. */ + +struct tdesc_parsing_data +{ + /* The target description we are building. */ + struct target_desc *tdesc; +}; + +/* Handle the end of an element and its value. */ + +static void +tdesc_end_arch (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, const char *body_text) +{ + struct tdesc_parsing_data *data = user_data; + const struct bfd_arch_info *arch; + + arch = bfd_scan_arch (body_text); + if (arch == NULL) + gdb_xml_error (parser, _("Target description specified unknown " + "architecture \"%s\""), body_text); + set_tdesc_architecture (data->tdesc, arch); +} + +/* The elements and attributes of an XML target description. */ + +const struct gdb_xml_element target_children[] = { + { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, + NULL, tdesc_end_arch }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +const struct gdb_xml_element tdesc_elements[] = { + { "target", NULL, target_children, GDB_XML_EF_NONE, + NULL, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +/* Parse DOCUMENT into a target description and return it. */ + +static struct target_desc * +tdesc_parse_xml (const char *document) +{ + struct cleanup *back_to, *result_cleanup; + struct gdb_xml_parser *parser; + struct tdesc_parsing_data data; + + memset (&data, 0, sizeof (struct tdesc_parsing_data)); + + back_to = make_cleanup (null_cleanup, NULL); + parser = gdb_xml_create_parser_and_cleanup (_("target description"), + tdesc_elements, &data); + + data.tdesc = allocate_target_description (); + result_cleanup = make_cleanup_free_target_description (data.tdesc); + + if (gdb_xml_parse (parser, document) == 0) + { + /* Parsed successfully. */ + discard_cleanups (result_cleanup); + do_cleanups (back_to); + return data.tdesc; + } + else + { + warning (_("Could not load XML target description; ignoring")); + do_cleanups (back_to); + return NULL; + } +} + +#endif /* HAVE_LIBEXPAT */ + + +/* Close FILE. */ + +static void +do_cleanup_fclose (void *file) +{ + fclose (file); +} + +/* Open FILENAME, read all its text into memory, close it, and return + the text. If something goes wrong, return NULL and warn. */ + +static char * +fetch_xml_from_file (const char *filename) +{ + FILE *file; + struct cleanup *back_to; + char *text; + size_t len, offset; + + file = fopen (filename, FOPEN_RT); + if (file == NULL) + { + warning (_("Could not open \"%s\""), filename); + return NULL; + } + back_to = make_cleanup (do_cleanup_fclose, file); + + /* Read in the whole file, one chunk at a time. */ + len = 4096; + offset = 0; + text = xmalloc (len); + make_cleanup (free_current_contents, &text); + while (1) + { + size_t bytes_read; + + /* Continue reading where the last read left off. Leave at least + one byte so that we can NUL-terminate the result. */ + bytes_read = fread (text + offset, 1, len - offset - 1, file); + if (ferror (file)) + { + warning (_("Read error from \"%s\""), filename); + do_cleanups (back_to); + return NULL; + } + + offset += bytes_read; + + if (feof (file)) + break; + + len = len * 2; + text = xrealloc (text, len); + } + + fclose (file); + discard_cleanups (back_to); + + text[offset] = '\0'; + return text; +} + +/* Read an XML target description from FILENAME. Parse it, and return + the parsed description. */ + +const struct target_desc * +file_read_description_xml (const char *filename) +{ + struct target_desc *tdesc; + char *tdesc_str; + struct cleanup *back_to; + + tdesc_str = fetch_xml_from_file (filename); + if (tdesc_str == NULL) + return NULL; + + back_to = make_cleanup (xfree, tdesc_str); + tdesc = tdesc_parse_xml (tdesc_str); + do_cleanups (back_to); + + return tdesc; +} + +/* Read an XML target description using OPS. Parse it, and return the + parsed description. */ + +const struct target_desc * +target_read_description_xml (struct target_ops *ops) +{ + struct target_desc *tdesc; + char *tdesc_str; + struct cleanup *back_to; + + tdesc_str = target_read_stralloc (ops, TARGET_OBJECT_AVAILABLE_FEATURES, + "target.xml"); + if (tdesc_str == NULL) + return NULL; + + back_to = make_cleanup (xfree, tdesc_str); + tdesc = tdesc_parse_xml (tdesc_str); + do_cleanups (back_to); + + return tdesc; +} diff --git a/gdb/xml-tdesc.h b/gdb/xml-tdesc.h new file mode 100644 index 00000000000..0f2a9d8379a --- /dev/null +++ b/gdb/xml-tdesc.h @@ -0,0 +1,36 @@ +/* XML target description support for GDB. + + Copyright (C) 2006 + Free Software Foundation, Inc. + + Contributed by CodeSourcery. + + 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. */ + +struct target_ops; +struct target_desc; + +/* Read an XML target description from FILENAME. Parse it, and return + the parsed description. */ + +const struct target_desc *file_read_description_xml (const char *filename); + +/* Read an XML target description using OPS. Parse it, and return the + parsed description. */ + +const struct target_desc *target_read_description_xml (struct target_ops *);