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