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