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