--- a/Makefile.in +++ b/Makefile.in @@ -731,7 +731,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr solib.c solib-target.c source.c \ stabsread.c stack.c probe.c stap-probe.c std-regs.c \ symfile.c symfile-mem.c symmisc.c symtab.c \ - target.c target-descriptions.c target-memory.c \ + target.c target-attributes.c target-descriptions.c target-memory.c \ thread.c top.c tracepoint.c \ trad-frame.c \ tramp-frame.c \ @@ -831,7 +831,8 @@ gnulib/import/extra/snippet/warn-on-use. gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \ common/format.h common/host-defs.h utils.h \ -common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h gdb_bfd.h +common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h gdb_bfd.h \ +target-attributes.h # Header files that already have srcdir in them, or which are in objdir. @@ -917,7 +918,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ solib.o solib-target.o \ prologue-value.o memory-map.o memrange.o \ xml-support.o xml-syscall.o xml-utils.o \ - target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \ + target-attributes.o target-descriptions.o target-memory.o \ + xml-tdesc.o xml-builtin.o \ inferior.o osdata.o gdb_usleep.o record.o gcore.o \ gdb_vecs.o jit.o progspace.o skip.o probe.o \ common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \ --- a/breakpoint.h +++ b/breakpoint.h @@ -700,6 +700,11 @@ struct breakpoint there is no condition. */ char *cond_string; + /* If True, the GDB side cannot do the condition check for + the condition of this breakpoint and this condition only can + be checked in agent side. */ + int target_only_cond_check; + /* String form of extra parameters, or NULL if there are none. */ char *extra_string; --- a/remote.c +++ b/remote.c @@ -43,6 +43,7 @@ #include "cli/cli-setshow.h" #include "target-descriptions.h" #include "gdb_bfd.h" +#include "target-attributes.h" #include #include @@ -1292,6 +1293,7 @@ enum { PACKET_qXfer_fdpic, PACKET_QDisableRandomization, PACKET_QAgent, + PACKET_qXfer_target_attributes_read, PACKET_MAX }; @@ -3510,6 +3512,22 @@ remote_start_remote (int from_tty, struc remote_check_symbols (symfile_objfile); } + if (remote_protocol_packets[PACKET_qXfer_target_attributes_read].support + != PACKET_DISABLE) + { + char *text; + + text = target_read_stralloc (¤t_target, TARGET_OBJECT_ATTRIBUTES, + NULL); + if (text != NULL) + { + struct cleanup *back_to = make_cleanup (xfree, text); + + add_xml_target_attributes (text); + do_cleanups (back_to); + } + } + /* Possibly the target has been engaged in a trace run started previously; find out where things are at. */ if (remote_get_trace_status (current_trace_status ()) != -1) @@ -3946,6 +3964,8 @@ static struct protocol_feature remote_pr { "QAgent", PACKET_DISABLE, remote_supported_packet, PACKET_QAgent}, { "tracenz", PACKET_DISABLE, remote_string_tracing_feature, -1 }, + { "qXfer:target-attributes:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_target_attributes_read }, }; static char *remote_support_xml; @@ -8672,6 +8692,12 @@ remote_xfer_partial (struct target_ops * return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len, &remote_protocol_packets[PACKET_qXfer_uib]); + case TARGET_OBJECT_ATTRIBUTES: + gdb_assert (annex == NULL); + return remote_read_qxfer + (ops, "target-attributes", annex, readbuf, offset, len, + &remote_protocol_packets[PACKET_qXfer_target_attributes_read]); + default: return -1; } @@ -11637,6 +11663,10 @@ Show the maximum size of the address (in add_packet_config_cmd (&remote_protocol_packets[PACKET_QAgent], "QAgent", "agent", 0); + add_packet_config_cmd + (&remote_protocol_packets[PACKET_qXfer_target_attributes_read], + "qXfer:target-attributes:read", "target-attributes", 0); + /* Keep the old ``set remote Z-packet ...'' working. Each individual Z sub-packet has its own set and show commands, but users may have sets to this variable in their .gdbinit files (or in their --- /dev/null +++ b/target-attributes.c @@ -0,0 +1,669 @@ +/* Target attributes for GDB, the GNU debugger. + + Copyright (C) 2012 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 3 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, see . */ + +#include "defs.h" +#include "gdb_string.h" +#include "ui-out.h" +#include "tracepoint.h" +#include "gdbcmd.h" +#include "target-attributes.h" + +static struct target_attribute *target_attributes_list; + +struct target_attribute * +find_target_attribute_name (const char *name) +{ + struct target_attribute *ta; + + for (ta = target_attributes_list; ta; ta = ta->next) + { + if (strcmp (ta->name, name) == 0) + return ta; + } + + return NULL; +} + +struct target_attribute * +find_target_attribute_id (int id) +{ + struct target_attribute *ta; + + for (ta = target_attributes_list; ta; ta = ta->next) + { + if (id == ta->id) + return ta; + } + + return NULL; +} + +static struct bp_location *check_agent_target_attribute_bl = NULL; +char *check_agent_target_attribute_error = NULL; + +static void +clear_check_agent_target_attribute (void *unused) +{ + check_agent_target_attribute_bl = NULL; +} + +struct cleanup * +set_check_agent_target_attribute (struct bp_location *bl) +{ + check_agent_target_attribute_bl = bl; + check_agent_target_attribute_error = NULL; + + return make_cleanup (clear_check_agent_target_attribute, NULL); +} + +void +check_agent_target_attribute (struct target_attribute *ta, int write) +{ + static char error_str[256]; + check_agent_target_attribute_error = error_str; + + if (write) + { + if ((ta->agent_access & TARGET_ATTRIBUTE_ACCESS_WRITE) == 0) + { + snprintf (error_str, 256, _("$%s cannot be written in agent code."), + ta->name); + error (_("$%s cannot be written in agent code."), ta->name); + } + } + else + { + if ((ta->agent_access & TARGET_ATTRIBUTE_ACCESS_READ) == 0) + { + snprintf (error_str, 256, _("$%s cannot be read in agent code."), + ta->name); + error (_("$%s cannot be read in agent code."), ta->name); + } + } + + if (check_agent_target_attribute_bl) + { + struct target_attribute_address *ta_addr; + + if (ta->target_only_cond_check) + check_agent_target_attribute_bl->owner->target_only_cond_check = 1; + + switch (check_agent_target_attribute_bl->loc_type) + { + case bp_loc_software_breakpoint: + if ((ta->support + & TARGET_ATTRIBUTE_SUPPORT_SOFTWARE_BREAKPOINT) == 0) + { + snprintf (error_str, 256, + _("$%s cannot be used in software breakpoint."), + ta->name); + error (_("$%s cannot be used in software breakpoint."), ta->name); + } + break; + case bp_loc_hardware_breakpoint: + if ((ta->support + & TARGET_ATTRIBUTE_SUPPORT_HARDWARE_BREAKPOINT) == 0) + { + snprintf (error_str, 256, + _("$%s cannot be used in hardware breakpoint."), + ta->name); + error (_("$%s cannot be used in hardware breakpoint."), + ta->name); + } + break; + case bp_loc_hardware_watchpoint: + if ((ta->support + & TARGET_ATTRIBUTE_SUPPORT_HARDWARE_WATCHPOINT) == 0) + { + snprintf (error_str, 256, + _("$%s cannot be used in hardware watchpoint."), + ta->name); + error (_("$%s cannot be used in hardware watchpoint."), + ta->name); + } + break; + default: + if (check_agent_target_attribute_bl->owner->type == bp_tracepoint + || check_agent_target_attribute_bl->owner->type + == bp_fast_tracepoint + || check_agent_target_attribute_bl->owner->type + == bp_static_tracepoint) + { + snprintf (error_str, 256, + _("$%s cannot be used in tracepoint."), ta->name); + if ((ta->support & TARGET_ATTRIBUTE_SUPPORT_TRACEPOINT) == 0) + error (_("$%s cannot be used in tracepoint."), ta->name); + } + else + { + snprintf (error_str, 256, + _("$%s cannot be used in breakpoint %d."), + ta->name, + check_agent_target_attribute_bl->owner->number); + error (_("$%s cannot be used in breakpoint %d."), ta->name, + check_agent_target_attribute_bl->owner->number); + } + break; + } + + if (ta->addresses) + { + for (ta_addr = ta->addresses; ta_addr; ta_addr = ta_addr->prev) + { + if (check_agent_target_attribute_bl->address >= ta_addr->start + && check_agent_target_attribute_bl->address <= ta_addr->end) + break; + } + if (!ta_addr) + { + snprintf (error_str, 256, + _("\ +$%s cannot be used in breakpoint %d because the address limit."), ta->name, + check_agent_target_attribute_bl->owner->number); + error (_("\ +$%s cannot be used in breakpoint %d because the address limit."), ta->name, + check_agent_target_attribute_bl->owner->number); + } + } + } + + check_agent_target_attribute_error = NULL; +} + +void +clear_target_attributes (void *unused) +{ + struct target_attribute *ta, *tmp; + + for (ta = target_attributes_list; ta;) + { + struct target_attribute_address *ta_addr, *tmp_addr; + + tmp = ta; + ta = ta->next; + + for (ta_addr = tmp->addresses; ta_addr;) + { + tmp_addr = ta_addr; + ta_addr = ta_addr->prev; + xfree (tmp_addr); + } + + xfree (tmp); + } + + target_attributes_list = NULL; +} + +static void +info_target_attributes (char *args, int from_tty) +{ + struct target_attribute *ta; + struct cleanup *back_to; + struct ui_out *uiout = current_uiout; + int count = 0; + + if (target_attributes_list == NULL) + { + ui_out_message (uiout, 0, _("No target attributes.\n")); + return; + } + + for (ta = target_attributes_list; ta; ta = ta->next) + count++; + + back_to = make_cleanup_ui_out_table_begin_end (uiout, 6, + count, "target-attributes"); + ui_out_table_header (uiout, 15, ui_left, "name", "Name"); + ui_out_table_header (uiout, 15, ui_left, "type", "Type"); + ui_out_table_header (uiout, 15, ui_left, "target-only-cond-check", + "Target-only-cond-check"); + ui_out_table_header (uiout, 15, ui_left, "agent access", "Agent access"); + ui_out_table_header (uiout, 15, ui_left, "gdb access", "GDB access"); + ui_out_table_header (uiout, 15, ui_left, "breakpoint type", + "Breakpoint type"); + + ui_out_table_body (uiout); + for (ta = target_attributes_list; ta; ta = ta->next) + { + struct target_attribute_address *ta_addr; + char buf[512]; + struct cleanup *back_to2 + = make_cleanup_ui_out_tuple_begin_end (uiout, "attributes"); + + snprintf (buf, 512, "$%s", ta->name); + ui_out_field_string (uiout, "name", buf); + + switch (ta->type) + { + case TARGET_ATTRIBUTE_TYPE_INT8: + ui_out_field_string (uiout, "type", "int8"); + break; + case TARGET_ATTRIBUTE_TYPE_UINT8: + ui_out_field_string (uiout, "type", "uint8"); + break; + case TARGET_ATTRIBUTE_TYPE_INT16: + ui_out_field_string (uiout, "type", "int16"); + break; + case TARGET_ATTRIBUTE_TYPE_UINT16: + ui_out_field_string (uiout, "type", "uint16"); + break; + case TARGET_ATTRIBUTE_TYPE_INT32: + ui_out_field_string (uiout, "type", "int32"); + break; + case TARGET_ATTRIBUTE_TYPE_UINT32: + ui_out_field_string (uiout, "type", "uint32"); + break; + case TARGET_ATTRIBUTE_TYPE_INT64: + ui_out_field_string (uiout, "type", "int64"); + break; + case TARGET_ATTRIBUTE_TYPE_UINT64: + ui_out_field_string (uiout, "type", "uint64"); + break; + } + + ui_out_field_string (uiout, "target-only-cond-check", + ta->target_only_cond_check ? "yes" : "no"); + + snprintf (buf, 512, "%s%s", + (ta->agent_access + & TARGET_ATTRIBUTE_ACCESS_READ) ? "read " : "", + (ta->agent_access + & TARGET_ATTRIBUTE_ACCESS_WRITE) ? "write" : ""); + ui_out_field_string (uiout, "agent access", buf); + + snprintf (buf, 512, "%s%s", + (ta->gdb_access & TARGET_ATTRIBUTE_ACCESS_READ) ? "read " : "", + (ta->gdb_access + & TARGET_ATTRIBUTE_ACCESS_WRITE) ? "write" : ""); + ui_out_field_string (uiout, "gdb access", buf); + + snprintf (buf, 512, "%s%s%s%s", + (ta->support & TARGET_ATTRIBUTE_SUPPORT_SOFTWARE_BREAKPOINT) + ? "software-breakpoint " : "", + (ta->support & TARGET_ATTRIBUTE_SUPPORT_HARDWARE_BREAKPOINT) + ? "hardware-breakpoint " : "", + (ta->support & TARGET_ATTRIBUTE_SUPPORT_HARDWARE_WATCHPOINT) + ? "hardware-watchpoint " : "", + (ta->support & TARGET_ATTRIBUTE_SUPPORT_TRACEPOINT) + ? "tracepoint " : ""); + ui_out_field_string (uiout, "breakpoint type", buf); + + ui_out_text (uiout, "\n"); + + for (ta_addr = ta->addresses; ta_addr; ta_addr = ta_addr->prev) + { + ui_out_spaces (uiout, 2); + ui_out_message (uiout, 0, "start:%s end:%s\n", + paddress (target_gdbarch, ta_addr->start), + paddress (target_gdbarch, ta_addr->end)); + } + do_cleanups (back_to2); + } + + do_cleanups (back_to); +} + +#if !defined(HAVE_LIBEXPAT) + +void +add_xml_target_attributes (const char *text) +{ + if (strlen (text) > 0) + warning (_("Can not parse XML target attributes; XML support " + "was disabled at compile time")); +} + +#else + +#include "xml-support.h" + +static void +target_attribute_attr_handler (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + char *name = NULL; + int i, len, id = -1, type = 0, target_only_cond_check = 0; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + struct target_attribute *ta, **tap = user_data; + + len = VEC_length (gdb_xml_value_s, attributes); + for (i = 0; i < len; i++) + { + if (strcmp (attrs[i].name, "name") == 0) + name = attrs[i].value; + else if (strcmp (attrs[i].name, "id") == 0) + id = * (ULONGEST *) attrs[i].value; + else if (strcmp (attrs[i].name, "type") == 0) + type = * (ULONGEST *) attrs[i].value; + else if (strcmp (attrs[i].name, "target-only-cond-check") == 0) + target_only_cond_check = * (ULONGEST *) attrs[i].value; + else + gdb_xml_error (parser, _("Unknown attribute name '%s'."), + attrs[i].name); + } + + if (!name || id < 0) + gdb_xml_error (parser, _("\"name\" or \"id\" is missed.")); + + if (find_target_attribute_name (name)) + gdb_xml_error (parser,_("\ +name \"%s\" is same with a target attribute."), name); + if (find_target_attribute_id (id)) + gdb_xml_error (parser,_("id \"%d\" is same with a target attribute."), id); + + ta = xzalloc (sizeof (struct target_attribute)); + ta->name = xstrdup (name); + ta->id = id; + ta->type = type; + ta->target_only_cond_check = target_only_cond_check; + + if (*tap) + (*tap)->next = ta; + else + target_attributes_list = ta; + *tap = ta; + + user_data = &ta; +} + +static void +target_attribute_access_children_handler (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + struct target_attribute *ta = *(struct target_attribute **)user_data; + int i, len, ta_access = 0; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + + len = VEC_length (gdb_xml_value_s, attributes); + for (i = 0; i < len; i++) + { + if (strcmp (attrs[i].name, "read") == 0) + { + if (* (ULONGEST *) attrs[i].value) + ta_access |= TARGET_ATTRIBUTE_ACCESS_READ; + } + else if (strcmp (attrs[i].name, "write") == 0) + { + if (* (ULONGEST *) attrs[i].value) + ta_access |= TARGET_ATTRIBUTE_ACCESS_WRITE; + } + else + gdb_xml_error (parser, _("Unknown attribute name '%s'."), + attrs[i].name); + } + + if (strcmp (element->name, "agent") == 0) + ta->agent_access = ta_access; + else + ta->gdb_access = ta_access; +} + +static void +target_attribute_support_attr_handler (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + struct target_attribute *ta = *(struct target_attribute **)user_data; + int i, len = 0; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + + len = VEC_length (gdb_xml_value_s, attributes); + for (i = 0; i < len; i++) + { + if (strcmp (attrs[i].name, "software-breakpoint") == 0) + { + if (* (ULONGEST *) attrs[i].value) + ta->support |= TARGET_ATTRIBUTE_SUPPORT_SOFTWARE_BREAKPOINT; + } + else if (strcmp (attrs[i].name, "hardware-breakpoint") == 0) + { + if (* (ULONGEST *) attrs[i].value) + ta->support |= TARGET_ATTRIBUTE_SUPPORT_HARDWARE_BREAKPOINT; + } + else if (strcmp (attrs[i].name, "hardware-watchpoint") == 0) + { + if (* (ULONGEST *) attrs[i].value) + ta->support |= TARGET_ATTRIBUTE_SUPPORT_HARDWARE_WATCHPOINT; + } + else if (strcmp (attrs[i].name, "tracepoint") == 0) + { + if (* (ULONGEST *) attrs[i].value) + ta->support |= TARGET_ATTRIBUTE_SUPPORT_TRACEPOINT; + } + else + gdb_xml_error (parser, _("Unknown attribute name '%s'."), + attrs[i].name); + } +} + +static void +target_attribute_address_handler (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + int i, len; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + struct target_attribute *ta = *(struct target_attribute **)user_data; + CORE_ADDR start = 0, end = 0; + struct target_attribute_address *ta_addr; + + len = VEC_length (gdb_xml_value_s, attributes); + for (i = 0; i < len; i++) + { + if (strcmp (attrs[i].name, "start") == 0) + start = * (ULONGEST *) attrs[i].value; + else if (strcmp (attrs[i].name, "end") == 0) + end = * (ULONGEST *) attrs[i].value; + else + gdb_xml_error (parser, _("Unknown attribute name '%s'."), + attrs[i].name); + } + + ta_addr = xmalloc (sizeof (struct target_attribute_address)); + ta_addr->start = start; + ta_addr->end = end; + + ta_addr->prev = ta->addresses; + ta->addresses = ta_addr; +} + +const struct gdb_xml_enum target_attribute_type_enums[] = { + { "int8", TARGET_ATTRIBUTE_TYPE_INT8 }, + { "uint8", TARGET_ATTRIBUTE_TYPE_UINT8 }, + { "int16", TARGET_ATTRIBUTE_TYPE_INT16 }, + { "uint16", TARGET_ATTRIBUTE_TYPE_UINT16 }, + { "int32", TARGET_ATTRIBUTE_TYPE_INT32 }, + { "uint32", TARGET_ATTRIBUTE_TYPE_UINT32 }, + { "int64", TARGET_ATTRIBUTE_TYPE_INT64 }, + { "uint64", TARGET_ATTRIBUTE_TYPE_UINT64 }, + { NULL, 0 } +}; + +static const struct gdb_xml_attribute target_attribute_attr[] = { + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "id", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "type", GDB_XML_AF_NONE, gdb_xml_parse_attr_enum, + target_attribute_type_enums }, + { "target-only-cond-check", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute + target_attribute_access_children_attr[] = { + { "read", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { "write", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element target_attribute_access_children[] = { + { "agent", target_attribute_access_children_attr, NULL, + GDB_XML_EF_OPTIONAL, target_attribute_access_children_handler, NULL }, + { "gdb", target_attribute_access_children_attr, NULL, + GDB_XML_EF_OPTIONAL, target_attribute_access_children_handler, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute target_attribute_support_attr[] = { + { "software-breakpoint", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { "hardware-breakpoint", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { "hardware-watchpoint", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { "tracepoint", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, + gdb_xml_enums_boolean }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute target_attribute_address_attr[] = { + { "start", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element target_attribute_addresses_children[] = { + { "address", target_attribute_address_attr, NULL, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + target_attribute_address_handler, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element target_attribute_elements[] = { + { "access", NULL, target_attribute_access_children, + GDB_XML_EF_NONE, NULL, NULL }, + { "support", target_attribute_support_attr, NULL, + GDB_XML_EF_OPTIONAL, target_attribute_support_attr_handler, NULL }, + { "addresses", NULL, target_attribute_addresses_children, + GDB_XML_EF_OPTIONAL, NULL, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element target_attributes_children[] = { + { "target-attribute", target_attribute_attr, target_attribute_elements, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + target_attribute_attr_handler, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element target_attributes_elements[] = { + { "target-attributes", NULL, target_attributes_children, + GDB_XML_EF_NONE, NULL, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +void +add_xml_target_attributes (const char *text) +{ + struct target_attribute *ta = NULL; + struct cleanup *back_to = make_cleanup (clear_target_attributes, NULL); + + clear_target_attributes(NULL); + if (gdb_xml_parse_quick (_("target attributes"), NULL, + target_attributes_elements, text, &ta) == 0) + { + discard_cleanups (back_to); + trace_variable_number_check (); + } + else + do_cleanups (back_to); +} + +#endif + +struct type * +target_attribute_type (struct gdbarch *gdbarch, struct target_attribute *ta) +{ + struct type *ret = builtin_type (gdbarch)->builtin_uint64; + + switch (ta->type) + { + case TARGET_ATTRIBUTE_TYPE_INT8: + ret = builtin_type (gdbarch)->builtin_int8; + break; + case TARGET_ATTRIBUTE_TYPE_UINT8: + ret = builtin_type (gdbarch)->builtin_uint8; + break; + case TARGET_ATTRIBUTE_TYPE_INT16: + ret = builtin_type (gdbarch)->builtin_int16; + break; + case TARGET_ATTRIBUTE_TYPE_UINT16: + ret = builtin_type (gdbarch)->builtin_uint16; + break; + case TARGET_ATTRIBUTE_TYPE_INT32: + ret = builtin_type (gdbarch)->builtin_int32; + break; + case TARGET_ATTRIBUTE_TYPE_UINT32: + ret = builtin_type (gdbarch)->builtin_uint32; + break; + case TARGET_ATTRIBUTE_TYPE_INT64: + ret = builtin_type (gdbarch)->builtin_int64; + break; + case TARGET_ATTRIBUTE_TYPE_UINT64: + ret = builtin_type (gdbarch)->builtin_uint64; + break; + } + + return ret; +} + +static void +load_target_attributes_command (char *exp, int from_tty) +{ + char *text = xml_fetch_content_from_file (exp, NULL); + + if (text == NULL) + error (_("Could not open \"%s\""), exp); + add_xml_target_attributes (text); +} + +static void +clear_target_attributes_command (char *exp, int from_tty) +{ + clear_target_attributes (NULL); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_targets_attributes; + +void +_initialize_targets_attributes (void) +{ + add_cmd ("load-target-attributes", class_maintenance, + load_target_attributes_command, + _("Load target attributes from a XML file."), + &maintenancelist); + + add_cmd ("clear-target-attributes", class_maintenance, + clear_target_attributes_command, + _("Remove all target attributes."), + &maintenancelist); + + add_info ("target-attributes", info_target_attributes, _("\ +Status of target attributes.")); +} --- /dev/null +++ b/target-attributes.h @@ -0,0 +1,104 @@ +/* Target attributes for GDB, the GNU debugger. + + Copyright (C) 2012 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 3 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, see . */ + +#ifndef TARGET_ATTRIBUTES_H +#define TARGET_ATTRIBUTES_H 1 + +enum +{ + TARGET_ATTRIBUTE_TYPE_INT8, + TARGET_ATTRIBUTE_TYPE_UINT8, + TARGET_ATTRIBUTE_TYPE_INT16, + TARGET_ATTRIBUTE_TYPE_UINT16, + TARGET_ATTRIBUTE_TYPE_INT32, + TARGET_ATTRIBUTE_TYPE_UINT32, + TARGET_ATTRIBUTE_TYPE_INT64, + TARGET_ATTRIBUTE_TYPE_UINT64, +}; + +#define TARGET_ATTRIBUTE_ACCESS_READ 0x1 +#define TARGET_ATTRIBUTE_ACCESS_WRITE 0x2 + +#define TARGET_ATTRIBUTE_SUPPORT_SOFTWARE_BREAKPOINT 0x1 +#define TARGET_ATTRIBUTE_SUPPORT_HARDWARE_BREAKPOINT 0x2 +#define TARGET_ATTRIBUTE_SUPPORT_HARDWARE_WATCHPOINT 0x4 +#define TARGET_ATTRIBUTE_SUPPORT_TRACEPOINT 0x8 + +struct target_attribute_address + { + struct target_attribute_address *prev; + CORE_ADDR start; + CORE_ADDR end; + }; + +/* This is the core struct of a target attribute. + When GDB get a target attribute from XML, + it will alloc a struct for it. */ + +struct target_attribute + { + struct target_attribute *next; + char *name; + int id; + int type; + int target_only_cond_check; + unsigned int agent_access; + unsigned int gdb_access; + unsigned int support; + struct target_attribute_address *addresses; + }; + +/* This is the error report string for function + check_agent_target_attribute. + Because some function call check_agent_target_attribute + with TRY_CATCH. Use this string report error. */ + +extern char *check_agent_target_attribute_error; + +extern struct target_attribute *find_target_attribute_name (const char *name); +extern struct target_attribute *find_target_attribute_id (int id); + +/* Set BL for function check_agent_target_attribute + before translate a string to agent expression bytecode. */ + +extern struct cleanup *set_check_agent_target_attribute + (struct bp_location *bl); + +/* The function that translate a string to agent expression bytecode call + check_agent_target_attribute to check if TA is OK to use with + BL that set by set_check_agent_target_attribute. */ + +extern void check_agent_target_attribute (struct target_attribute *ta, + int write); + +/* Remove all the target attributes inside the GDB. */ + +extern void clear_target_attributes (void *unused); + +/* Parse target attributes out from XML formart string TEXT + and add them to GDB. */ + +extern void add_xml_target_attributes (const char *text); + +/* Return the type of TA. */ + +extern struct type *target_attribute_type (struct gdbarch *gdbarch, + struct target_attribute *ta); + +#endif /* TARGET_ATTRIBUTES_H */ --- a/target.h +++ b/target.h @@ -286,7 +286,9 @@ enum target_object /* Darwin dynamic linker info data. */ TARGET_OBJECT_DARWIN_DYLD_INFO, /* OpenVMS Unwind Information Block. */ - TARGET_OBJECT_OPENVMS_UIB + TARGET_OBJECT_OPENVMS_UIB, + /* Target attributes. */ + TARGET_OBJECT_ATTRIBUTES, /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; --- a/tracepoint.c +++ b/tracepoint.c @@ -53,6 +53,7 @@ #include "exceptions.h" #include "cli/cli-utils.h" #include "probe.h" +#include "target-attributes.h" /* readline include files */ #include "readline/readline.h" @@ -348,6 +349,21 @@ find_trace_state_variable (const char *n return NULL; } +/* Look for a trace state variable of the given number. */ + +static struct trace_state_variable * +find_trace_state_variable_number (int number) +{ + struct trace_state_variable *tsv; + int ix; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + if (number == tsv->number) + return tsv; + + return NULL; +} + static void delete_trace_state_variable (const char *name) { @@ -365,6 +381,41 @@ delete_trace_state_variable (const char warning (_("No trace variable named \"$%s\", not deleting"), name); } +static int +trace_variable_number_check_1 (struct trace_state_variable *tsv) +{ + if (find_target_attribute_id (tsv->number)) + { + int new_number = tsv->number + 1; + tsv->number = 0; + while (find_target_attribute_id (new_number) + || find_trace_state_variable_number (new_number)) + new_number++; + tsv->number = new_number; + + return 1; + } + + return 0; +} + +void +trace_variable_number_check (void) +{ + struct trace_state_variable *tsv; + int ix; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + if (trace_variable_number_check_1 (tsv)) + { + warning (_("\ +number of trace variable $%s is same with a tsv compatible \n\ +target attribute. So it is changed to %d."), tsv->name, tsv->number); + } + } +} + /* The 'tvariable' command collects a name and optional expression to evaluate into an initial value. */ @@ -423,6 +474,8 @@ trace_variable_command (char *args, int tsv = create_trace_state_variable (internalvar_name (intvar)); tsv->initial_value = initval; + trace_variable_number_check_1 (tsv); + printf_filtered (_("Trace state variable $%s " "created, with initial value %s.\n"), tsv->name, plongest (tsv->initial_value)); @@ -3602,6 +3655,8 @@ merge_uploaded_trace_state_variables (st if (tsv->number == 0) tsv->number = highest++; + trace_variable_number_check(); + free_uploaded_tsvs (uploaded_tsvs); } --- a/tracepoint.h +++ b/tracepoint.h @@ -250,6 +250,8 @@ extern void while_stepping_pseudocommand extern struct trace_state_variable *find_trace_state_variable (const char *name); extern struct trace_state_variable *create_trace_state_variable (const char *name); +extern void trace_variable_number_check(void); + extern int encode_source_string (int num, ULONGEST addr, char *srctype, char *src, char *buf, int buf_size);