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