Home | History | Annotate | Line # | Download | only in gdb
osdata.c revision 1.8
      1  1.1  christos /* Routines for handling XML generic OS data provided by target.
      2  1.1  christos 
      3  1.8  christos    Copyright (C) 2008-2019 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    This file is part of GDB.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify
      8  1.1  christos    it under the terms of the GNU General Public License as published by
      9  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10  1.1  christos    (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  christos    GNU General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU General Public License
     18  1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19  1.1  christos 
     20  1.1  christos #include "defs.h"
     21  1.1  christos #include "target.h"
     22  1.8  christos #include "common/vec.h"
     23  1.1  christos #include "xml-support.h"
     24  1.1  christos #include "osdata.h"
     25  1.1  christos #include "ui-out.h"
     26  1.1  christos #include "gdbcmd.h"
     27  1.1  christos 
     28  1.1  christos #if !defined(HAVE_LIBEXPAT)
     29  1.1  christos 
     30  1.8  christos std::unique_ptr<osdata>
     31  1.1  christos osdata_parse (const char *xml)
     32  1.1  christos {
     33  1.1  christos   static int have_warned;
     34  1.1  christos 
     35  1.1  christos   if (!have_warned)
     36  1.1  christos     {
     37  1.1  christos       have_warned = 1;
     38  1.1  christos       warning (_("Can not parse XML OS data; XML support was disabled "
     39  1.1  christos                 "at compile time"));
     40  1.1  christos     }
     41  1.1  christos 
     42  1.1  christos   return NULL;
     43  1.1  christos }
     44  1.1  christos 
     45  1.1  christos #else /* HAVE_LIBEXPAT */
     46  1.1  christos 
     47  1.1  christos /* Internal parsing data passed to all XML callbacks.  */
     48  1.1  christos struct osdata_parsing_data
     49  1.8  christos {
     50  1.8  christos   std::unique_ptr<struct osdata> osdata;
     51  1.8  christos   std::string property_name;
     52  1.8  christos };
     53  1.1  christos 
     54  1.1  christos /* Handle the start of a <osdata> element.  */
     55  1.1  christos 
     56  1.1  christos static void
     57  1.1  christos osdata_start_osdata (struct gdb_xml_parser *parser,
     58  1.1  christos                         const struct gdb_xml_element *element,
     59  1.8  christos                         void *user_data,
     60  1.8  christos 			std::vector<gdb_xml_value> &attributes)
     61  1.1  christos {
     62  1.6  christos   struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
     63  1.1  christos 
     64  1.8  christos   if (data->osdata != NULL)
     65  1.1  christos     gdb_xml_error (parser, _("Seen more than on osdata element"));
     66  1.1  christos 
     67  1.8  christos   char *type = (char *) xml_find_attribute (attributes, "type")->value.get ();
     68  1.8  christos   data->osdata.reset (new struct osdata (std::string (type)));
     69  1.1  christos }
     70  1.1  christos 
     71  1.1  christos /* Handle the start of a <item> element.  */
     72  1.1  christos 
     73  1.1  christos static void
     74  1.1  christos osdata_start_item (struct gdb_xml_parser *parser,
     75  1.1  christos                   const struct gdb_xml_element *element,
     76  1.8  christos                   void *user_data,
     77  1.8  christos 		  std::vector<gdb_xml_value> &attributes)
     78  1.1  christos {
     79  1.6  christos   struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
     80  1.8  christos   data->osdata->items.emplace_back ();
     81  1.1  christos }
     82  1.1  christos 
     83  1.1  christos /* Handle the start of a <column> element.  */
     84  1.1  christos 
     85  1.1  christos static void
     86  1.1  christos osdata_start_column (struct gdb_xml_parser *parser,
     87  1.1  christos                     const struct gdb_xml_element *element,
     88  1.8  christos                     void *user_data,
     89  1.8  christos 		    std::vector<gdb_xml_value> &attributes)
     90  1.1  christos {
     91  1.6  christos   struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
     92  1.6  christos   const char *name
     93  1.8  christos     = (const char *) xml_find_attribute (attributes, "name")->value.get ();
     94  1.1  christos 
     95  1.8  christos   data->property_name.assign (name);
     96  1.1  christos }
     97  1.1  christos 
     98  1.1  christos /* Handle the end of a <column> element.  */
     99  1.1  christos 
    100  1.1  christos static void
    101  1.1  christos osdata_end_column (struct gdb_xml_parser *parser,
    102  1.1  christos                   const struct gdb_xml_element *element,
    103  1.1  christos                   void *user_data, const char *body_text)
    104  1.1  christos {
    105  1.8  christos   osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
    106  1.8  christos   struct osdata *osdata = data->osdata.get ();
    107  1.8  christos   osdata_item &item = osdata->items.back ();
    108  1.1  christos 
    109  1.8  christos   item.columns.emplace_back (std::move (data->property_name),
    110  1.8  christos 			     std::string (body_text));
    111  1.1  christos }
    112  1.1  christos 
    113  1.1  christos /* The allowed elements and attributes for OS data object.
    114  1.1  christos    The root element is a <osdata>.  */
    115  1.1  christos 
    116  1.1  christos const struct gdb_xml_attribute column_attributes[] = {
    117  1.1  christos   { "name", GDB_XML_AF_NONE, NULL, NULL },
    118  1.1  christos   { NULL, GDB_XML_AF_NONE, NULL, NULL }
    119  1.1  christos };
    120  1.1  christos 
    121  1.1  christos const struct gdb_xml_element item_children[] = {
    122  1.1  christos   { "column", column_attributes, NULL,
    123  1.1  christos     GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
    124  1.1  christos     osdata_start_column, osdata_end_column },
    125  1.1  christos   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
    126  1.1  christos };
    127  1.1  christos 
    128  1.1  christos const struct gdb_xml_attribute osdata_attributes[] = {
    129  1.1  christos   { "type", GDB_XML_AF_NONE, NULL, NULL },
    130  1.1  christos   { NULL, GDB_XML_AF_NONE, NULL, NULL }
    131  1.1  christos };
    132  1.1  christos 
    133  1.1  christos const struct gdb_xml_element osdata_children[] = {
    134  1.1  christos   { "item", NULL, item_children,
    135  1.1  christos     GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
    136  1.1  christos     osdata_start_item, NULL },
    137  1.1  christos   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
    138  1.1  christos };
    139  1.1  christos 
    140  1.1  christos const struct gdb_xml_element osdata_elements[] = {
    141  1.1  christos   { "osdata", osdata_attributes, osdata_children,
    142  1.1  christos     GDB_XML_EF_NONE, osdata_start_osdata, NULL },
    143  1.1  christos   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
    144  1.1  christos };
    145  1.1  christos 
    146  1.8  christos std::unique_ptr<osdata>
    147  1.1  christos osdata_parse (const char *xml)
    148  1.1  christos {
    149  1.8  christos   osdata_parsing_data data;
    150  1.1  christos 
    151  1.1  christos   if (gdb_xml_parse_quick (_("osdata"), "osdata.dtd",
    152  1.1  christos 			   osdata_elements, xml, &data) == 0)
    153  1.1  christos     {
    154  1.1  christos       /* Parsed successfully, don't need to delete the result.  */
    155  1.8  christos       return std::move (data.osdata);
    156  1.1  christos     }
    157  1.1  christos 
    158  1.1  christos   return NULL;
    159  1.1  christos }
    160  1.1  christos #endif
    161  1.1  christos 
    162  1.8  christos std::unique_ptr<osdata>
    163  1.1  christos get_osdata (const char *type)
    164  1.1  christos {
    165  1.8  christos   std::unique_ptr<osdata> osdata;
    166  1.8  christos   gdb::optional<gdb::char_vector> xml = target_get_osdata (type);
    167  1.1  christos 
    168  1.1  christos   if (xml)
    169  1.1  christos     {
    170  1.8  christos       if ((*xml)[0] == '\0')
    171  1.1  christos 	{
    172  1.1  christos 	  if (type)
    173  1.1  christos 	    warning (_("Empty data returned by target.  Wrong osdata type?"));
    174  1.1  christos 	  else
    175  1.1  christos 	    warning (_("Empty type list returned by target.  No type data?"));
    176  1.1  christos 	}
    177  1.1  christos       else
    178  1.8  christos 	osdata = osdata_parse (xml->data ());
    179  1.1  christos     }
    180  1.1  christos 
    181  1.8  christos   if (osdata == NULL)
    182  1.1  christos     error (_("Can not fetch data now."));
    183  1.1  christos 
    184  1.1  christos   return osdata;
    185  1.1  christos }
    186  1.1  christos 
    187  1.8  christos const std::string *
    188  1.8  christos get_osdata_column (const osdata_item &item, const char *name)
    189  1.1  christos {
    190  1.8  christos   for (const osdata_column &col : item.columns)
    191  1.8  christos     if (col.name == name)
    192  1.8  christos       return &col.value;
    193  1.1  christos 
    194  1.1  christos   return NULL;
    195  1.1  christos }
    196  1.1  christos 
    197  1.1  christos void
    198  1.7  christos info_osdata (const char *type)
    199  1.1  christos {
    200  1.1  christos   struct ui_out *uiout = current_uiout;
    201  1.1  christos   struct osdata_item *last = NULL;
    202  1.1  christos   int ncols = 0;
    203  1.1  christos   int col_to_skip = -1;
    204  1.1  christos 
    205  1.7  christos   if (type == NULL)
    206  1.7  christos     type = "";
    207  1.7  christos 
    208  1.8  christos   std::unique_ptr<osdata> osdata = get_osdata (type);
    209  1.1  christos 
    210  1.8  christos   int nrows = osdata->items.size ();
    211  1.1  christos 
    212  1.7  christos   if (*type == '\0' && nrows == 0)
    213  1.1  christos     error (_("Available types of OS data not reported."));
    214  1.1  christos 
    215  1.8  christos   if (!osdata->items.empty ())
    216  1.1  christos     {
    217  1.8  christos       last = &osdata->items.back ();
    218  1.8  christos       ncols = last->columns.size ();
    219  1.1  christos 
    220  1.1  christos       /* As a special case, scan the listing of available data types
    221  1.1  christos 	 for a column named "Title", and only include it with MI
    222  1.1  christos 	 output; this column's normal use is for titles for interface
    223  1.1  christos 	 elements like menus, and it clutters up CLI output.  */
    224  1.7  christos       if (*type == '\0' && !uiout->is_mi_like_p ())
    225  1.1  christos 	{
    226  1.8  christos 	  for (int ix = 0; ix < last->columns.size (); ix++)
    227  1.1  christos 	    {
    228  1.8  christos 	      if (last->columns[ix].name == "Title")
    229  1.1  christos 		col_to_skip = ix;
    230  1.1  christos 	    }
    231  1.1  christos 	  /* Be sure to reduce the total column count, otherwise
    232  1.1  christos 	     internal errors ensue.  */
    233  1.1  christos 	  if (col_to_skip >= 0)
    234  1.1  christos 	    --ncols;
    235  1.1  christos 	}
    236  1.1  christos     }
    237  1.1  christos 
    238  1.8  christos   ui_out_emit_table table_emitter (uiout, ncols, nrows, "OSDataTable");
    239  1.1  christos 
    240  1.1  christos   /* With no columns/items, we just output an empty table, but we
    241  1.1  christos      still output the table.  This matters for MI.  */
    242  1.1  christos   if (ncols == 0)
    243  1.8  christos     return;
    244  1.1  christos 
    245  1.8  christos   if (last != NULL && !last->columns.empty ())
    246  1.1  christos     {
    247  1.8  christos       for (int ix = 0; ix < last->columns.size (); ix++)
    248  1.1  christos 	{
    249  1.1  christos 	  char col_name[32];
    250  1.1  christos 
    251  1.1  christos 	  if (ix == col_to_skip)
    252  1.1  christos 	    continue;
    253  1.1  christos 
    254  1.1  christos 	  snprintf (col_name, 32, "col%d", ix);
    255  1.7  christos 	  uiout->table_header (10, ui_left,
    256  1.8  christos 			       col_name, last->columns[ix].name.c_str ());
    257  1.1  christos         }
    258  1.1  christos     }
    259  1.1  christos 
    260  1.7  christos   uiout->table_body ();
    261  1.1  christos 
    262  1.1  christos   if (nrows != 0)
    263  1.1  christos     {
    264  1.8  christos       for (const osdata_item &item : osdata->items)
    265  1.8  christos        {
    266  1.8  christos 	 {
    267  1.8  christos 	   ui_out_emit_tuple tuple_emitter (uiout, "item");
    268  1.1  christos 
    269  1.8  christos 	   for (int ix_cols = 0; ix_cols < item.columns.size (); ix_cols++)
    270  1.8  christos 	     {
    271  1.8  christos 	       char col_name[32];
    272  1.8  christos 
    273  1.8  christos 	       if (ix_cols == col_to_skip)
    274  1.8  christos 		 continue;
    275  1.8  christos 
    276  1.8  christos 	       snprintf (col_name, 32, "col%d", ix_cols);
    277  1.8  christos 	       uiout->field_string (col_name,
    278  1.8  christos 				    item.columns[ix_cols].value.c_str ());
    279  1.8  christos 	     }
    280  1.8  christos 	 }
    281  1.1  christos 
    282  1.7  christos          uiout->text ("\n");
    283  1.1  christos        }
    284  1.1  christos     }
    285  1.1  christos }
    286  1.1  christos 
    287  1.7  christos static void
    288  1.8  christos info_osdata_command (const char *arg, int from_tty)
    289  1.7  christos {
    290  1.7  christos   info_osdata (arg);
    291  1.7  christos }
    292  1.7  christos 
    293  1.1  christos void
    294  1.1  christos _initialize_osdata (void)
    295  1.1  christos {
    296  1.1  christos   add_info ("os", info_osdata_command,
    297  1.1  christos            _("Show OS data ARG."));
    298  1.1  christos }
    299