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