1 | /* |
2 | * QEMU monitor |
3 | * |
4 | * Copyright (c) 2003-2004 Fabrice Bellard |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to deal |
8 | * in the Software without restriction, including without limitation the rights |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | * copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | * THE SOFTWARE. |
23 | */ |
24 | |
25 | #include "qemu/osdep.h" |
26 | #include "monitor-internal.h" |
27 | #include "cpu.h" |
28 | #include "monitor/qdev.h" |
29 | #include "hw/usb.h" |
30 | #include "hw/pci/pci.h" |
31 | #include "sysemu/watchdog.h" |
32 | #include "hw/loader.h" |
33 | #include "exec/gdbstub.h" |
34 | #include "net/net.h" |
35 | #include "net/slirp.h" |
36 | #include "chardev/char-mux.h" |
37 | #include "ui/qemu-spice.h" |
38 | #include "qemu/config-file.h" |
39 | #include "qemu/ctype.h" |
40 | #include "ui/console.h" |
41 | #include "ui/input.h" |
42 | #include "audio/audio.h" |
43 | #include "disas/disas.h" |
44 | #include "sysemu/balloon.h" |
45 | #include "qemu/timer.h" |
46 | #include "sysemu/hw_accel.h" |
47 | #include "sysemu/runstate.h" |
48 | #include "authz/list.h" |
49 | #include "qapi/util.h" |
50 | #include "sysemu/blockdev.h" |
51 | #include "sysemu/sysemu.h" |
52 | #include "sysemu/tcg.h" |
53 | #include "sysemu/tpm.h" |
54 | #include "qapi/qmp/qdict.h" |
55 | #include "qapi/qmp/qerror.h" |
56 | #include "qapi/qmp/qstring.h" |
57 | #include "qom/object_interfaces.h" |
58 | #include "trace/control.h" |
59 | #include "monitor/hmp-target.h" |
60 | #include "monitor/hmp.h" |
61 | #ifdef CONFIG_TRACE_SIMPLE |
62 | #include "trace/simple.h" |
63 | #endif |
64 | #include "exec/memory.h" |
65 | #include "exec/exec-all.h" |
66 | #include "qemu/option.h" |
67 | #include "qemu/thread.h" |
68 | #include "block/qapi.h" |
69 | #include "qapi/qapi-commands.h" |
70 | #include "qapi/qapi-emit-events.h" |
71 | #include "qapi/error.h" |
72 | #include "qapi/qmp-event.h" |
73 | #include "qapi/qapi-introspect.h" |
74 | #include "sysemu/cpus.h" |
75 | #include "qemu/cutils.h" |
76 | #include "tcg/tcg.h" |
77 | |
78 | #if defined(TARGET_S390X) |
79 | #include "hw/s390x/storage-keys.h" |
80 | #include "hw/s390x/storage-attributes.h" |
81 | #endif |
82 | |
83 | /* file descriptors passed via SCM_RIGHTS */ |
84 | typedef struct mon_fd_t mon_fd_t; |
85 | struct mon_fd_t { |
86 | char *name; |
87 | int fd; |
88 | QLIST_ENTRY(mon_fd_t) next; |
89 | }; |
90 | |
91 | /* file descriptor associated with a file descriptor set */ |
92 | typedef struct MonFdsetFd MonFdsetFd; |
93 | struct MonFdsetFd { |
94 | int fd; |
95 | bool removed; |
96 | char *opaque; |
97 | QLIST_ENTRY(MonFdsetFd) next; |
98 | }; |
99 | |
100 | /* file descriptor set containing fds passed via SCM_RIGHTS */ |
101 | typedef struct MonFdset MonFdset; |
102 | struct MonFdset { |
103 | int64_t id; |
104 | QLIST_HEAD(, MonFdsetFd) fds; |
105 | QLIST_HEAD(, MonFdsetFd) dup_fds; |
106 | QLIST_ENTRY(MonFdset) next; |
107 | }; |
108 | |
109 | /* QMP checker flags */ |
110 | #define QMP_ACCEPT_UNKNOWNS 1 |
111 | |
112 | /* Protects mon_fdsets */ |
113 | static QemuMutex mon_fdsets_lock; |
114 | static QLIST_HEAD(, MonFdset) mon_fdsets; |
115 | |
116 | static HMPCommand hmp_info_cmds[]; |
117 | |
118 | char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, |
119 | int64_t cpu_index, Error **errp) |
120 | { |
121 | char *output = NULL; |
122 | Monitor *old_mon; |
123 | MonitorHMP hmp = {}; |
124 | |
125 | monitor_data_init(&hmp.common, false, true, false); |
126 | |
127 | old_mon = cur_mon; |
128 | cur_mon = &hmp.common; |
129 | |
130 | if (has_cpu_index) { |
131 | int ret = monitor_set_cpu(cpu_index); |
132 | if (ret < 0) { |
133 | cur_mon = old_mon; |
134 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index" , |
135 | "a CPU number" ); |
136 | goto out; |
137 | } |
138 | } |
139 | |
140 | handle_hmp_command(&hmp, command_line); |
141 | cur_mon = old_mon; |
142 | |
143 | qemu_mutex_lock(&hmp.common.mon_lock); |
144 | if (qstring_get_length(hmp.common.outbuf) > 0) { |
145 | output = g_strdup(qstring_get_str(hmp.common.outbuf)); |
146 | } else { |
147 | output = g_strdup("" ); |
148 | } |
149 | qemu_mutex_unlock(&hmp.common.mon_lock); |
150 | |
151 | out: |
152 | monitor_data_destroy(&hmp.common); |
153 | return output; |
154 | } |
155 | |
156 | /** |
157 | * Is @name in the '|' separated list of names @list? |
158 | */ |
159 | int hmp_compare_cmd(const char *name, const char *list) |
160 | { |
161 | const char *p, *pstart; |
162 | int len; |
163 | len = strlen(name); |
164 | p = list; |
165 | for (;;) { |
166 | pstart = p; |
167 | p = qemu_strchrnul(p, '|'); |
168 | if ((p - pstart) == len && !memcmp(pstart, name, len)) { |
169 | return 1; |
170 | } |
171 | if (*p == '\0') { |
172 | break; |
173 | } |
174 | p++; |
175 | } |
176 | return 0; |
177 | } |
178 | |
179 | static void do_help_cmd(Monitor *mon, const QDict *qdict) |
180 | { |
181 | help_cmd(mon, qdict_get_try_str(qdict, "name" )); |
182 | } |
183 | |
184 | static void hmp_trace_event(Monitor *mon, const QDict *qdict) |
185 | { |
186 | const char *tp_name = qdict_get_str(qdict, "name" ); |
187 | bool new_state = qdict_get_bool(qdict, "option" ); |
188 | bool has_vcpu = qdict_haskey(qdict, "vcpu" ); |
189 | int vcpu = qdict_get_try_int(qdict, "vcpu" , 0); |
190 | Error *local_err = NULL; |
191 | |
192 | if (vcpu < 0) { |
193 | monitor_printf(mon, "argument vcpu must be positive" ); |
194 | return; |
195 | } |
196 | |
197 | qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err); |
198 | if (local_err) { |
199 | error_report_err(local_err); |
200 | } |
201 | } |
202 | |
203 | #ifdef CONFIG_TRACE_SIMPLE |
204 | static void hmp_trace_file(Monitor *mon, const QDict *qdict) |
205 | { |
206 | const char *op = qdict_get_try_str(qdict, "op" ); |
207 | const char *arg = qdict_get_try_str(qdict, "arg" ); |
208 | |
209 | if (!op) { |
210 | st_print_trace_file_status(); |
211 | } else if (!strcmp(op, "on" )) { |
212 | st_set_trace_file_enabled(true); |
213 | } else if (!strcmp(op, "off" )) { |
214 | st_set_trace_file_enabled(false); |
215 | } else if (!strcmp(op, "flush" )) { |
216 | st_flush_trace_buffer(); |
217 | } else if (!strcmp(op, "set" )) { |
218 | if (arg) { |
219 | st_set_trace_file(arg); |
220 | } |
221 | } else { |
222 | monitor_printf(mon, "unexpected argument \"%s\"\n" , op); |
223 | help_cmd(mon, "trace-file" ); |
224 | } |
225 | } |
226 | #endif |
227 | |
228 | static void hmp_info_help(Monitor *mon, const QDict *qdict) |
229 | { |
230 | help_cmd(mon, "info" ); |
231 | } |
232 | |
233 | static void query_commands_cb(QmpCommand *cmd, void *opaque) |
234 | { |
235 | CommandInfoList *info, **list = opaque; |
236 | |
237 | if (!cmd->enabled) { |
238 | return; |
239 | } |
240 | |
241 | info = g_malloc0(sizeof(*info)); |
242 | info->value = g_malloc0(sizeof(*info->value)); |
243 | info->value->name = g_strdup(cmd->name); |
244 | info->next = *list; |
245 | *list = info; |
246 | } |
247 | |
248 | CommandInfoList *qmp_query_commands(Error **errp) |
249 | { |
250 | CommandInfoList *list = NULL; |
251 | MonitorQMP *mon; |
252 | |
253 | assert(monitor_is_qmp(cur_mon)); |
254 | mon = container_of(cur_mon, MonitorQMP, common); |
255 | |
256 | qmp_for_each_command(mon->commands, query_commands_cb, &list); |
257 | |
258 | return list; |
259 | } |
260 | |
261 | EventInfoList *qmp_query_events(Error **errp) |
262 | { |
263 | /* |
264 | * TODO This deprecated command is the only user of |
265 | * QAPIEvent_str() and QAPIEvent_lookup[]. When the command goes, |
266 | * they should go, too. |
267 | */ |
268 | EventInfoList *info, *ev_list = NULL; |
269 | QAPIEvent e; |
270 | |
271 | for (e = 0 ; e < QAPI_EVENT__MAX ; e++) { |
272 | const char *event_name = QAPIEvent_str(e); |
273 | assert(event_name != NULL); |
274 | info = g_malloc0(sizeof(*info)); |
275 | info->value = g_malloc0(sizeof(*info->value)); |
276 | info->value->name = g_strdup(event_name); |
277 | |
278 | info->next = ev_list; |
279 | ev_list = info; |
280 | } |
281 | |
282 | return ev_list; |
283 | } |
284 | |
285 | /* |
286 | * Minor hack: generated marshalling suppressed for this command |
287 | * ('gen': false in the schema) so we can parse the JSON string |
288 | * directly into QObject instead of first parsing it with |
289 | * visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it |
290 | * to QObject with generated output marshallers, every time. Instead, |
291 | * we do it in test-qobject-input-visitor.c, just to make sure |
292 | * qapi-gen.py's output actually conforms to the schema. |
293 | */ |
294 | static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, |
295 | Error **errp) |
296 | { |
297 | *ret_data = qobject_from_qlit(&qmp_schema_qlit); |
298 | } |
299 | |
300 | static void monitor_init_qmp_commands(void) |
301 | { |
302 | /* |
303 | * Two command lists: |
304 | * - qmp_commands contains all QMP commands |
305 | * - qmp_cap_negotiation_commands contains just |
306 | * "qmp_capabilities", to enforce capability negotiation |
307 | */ |
308 | |
309 | qmp_init_marshal(&qmp_commands); |
310 | |
311 | qmp_register_command(&qmp_commands, "query-qmp-schema" , |
312 | qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG); |
313 | qmp_register_command(&qmp_commands, "device_add" , qmp_device_add, |
314 | QCO_NO_OPTIONS); |
315 | qmp_register_command(&qmp_commands, "netdev_add" , qmp_netdev_add, |
316 | QCO_NO_OPTIONS); |
317 | |
318 | QTAILQ_INIT(&qmp_cap_negotiation_commands); |
319 | qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities" , |
320 | qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG); |
321 | } |
322 | |
323 | /* |
324 | * Accept QMP capabilities in @list for @mon. |
325 | * On success, set mon->qmp.capab[], and return true. |
326 | * On error, set @errp, and return false. |
327 | */ |
328 | static bool qmp_caps_accept(MonitorQMP *mon, QMPCapabilityList *list, |
329 | Error **errp) |
330 | { |
331 | GString *unavailable = NULL; |
332 | bool capab[QMP_CAPABILITY__MAX]; |
333 | |
334 | memset(capab, 0, sizeof(capab)); |
335 | |
336 | for (; list; list = list->next) { |
337 | if (!mon->capab_offered[list->value]) { |
338 | if (!unavailable) { |
339 | unavailable = g_string_new(QMPCapability_str(list->value)); |
340 | } else { |
341 | g_string_append_printf(unavailable, ", %s" , |
342 | QMPCapability_str(list->value)); |
343 | } |
344 | } |
345 | capab[list->value] = true; |
346 | } |
347 | |
348 | if (unavailable) { |
349 | error_setg(errp, "Capability %s not available" , unavailable->str); |
350 | g_string_free(unavailable, true); |
351 | return false; |
352 | } |
353 | |
354 | memcpy(mon->capab, capab, sizeof(capab)); |
355 | return true; |
356 | } |
357 | |
358 | void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, |
359 | Error **errp) |
360 | { |
361 | MonitorQMP *mon; |
362 | |
363 | assert(monitor_is_qmp(cur_mon)); |
364 | mon = container_of(cur_mon, MonitorQMP, common); |
365 | |
366 | if (mon->commands == &qmp_commands) { |
367 | error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, |
368 | "Capabilities negotiation is already complete, command " |
369 | "ignored" ); |
370 | return; |
371 | } |
372 | |
373 | if (!qmp_caps_accept(mon, enable, errp)) { |
374 | return; |
375 | } |
376 | |
377 | mon->commands = &qmp_commands; |
378 | } |
379 | |
380 | /* Set the current CPU defined by the user. Callers must hold BQL. */ |
381 | int monitor_set_cpu(int cpu_index) |
382 | { |
383 | CPUState *cpu; |
384 | |
385 | cpu = qemu_get_cpu(cpu_index); |
386 | if (cpu == NULL) { |
387 | return -1; |
388 | } |
389 | g_free(cur_mon->mon_cpu_path); |
390 | cur_mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); |
391 | return 0; |
392 | } |
393 | |
394 | /* Callers must hold BQL. */ |
395 | static CPUState *mon_get_cpu_sync(bool synchronize) |
396 | { |
397 | CPUState *cpu; |
398 | |
399 | if (cur_mon->mon_cpu_path) { |
400 | cpu = (CPUState *) object_resolve_path_type(cur_mon->mon_cpu_path, |
401 | TYPE_CPU, NULL); |
402 | if (!cpu) { |
403 | g_free(cur_mon->mon_cpu_path); |
404 | cur_mon->mon_cpu_path = NULL; |
405 | } |
406 | } |
407 | if (!cur_mon->mon_cpu_path) { |
408 | if (!first_cpu) { |
409 | return NULL; |
410 | } |
411 | monitor_set_cpu(first_cpu->cpu_index); |
412 | cpu = first_cpu; |
413 | } |
414 | if (synchronize) { |
415 | cpu_synchronize_state(cpu); |
416 | } |
417 | return cpu; |
418 | } |
419 | |
420 | CPUState *mon_get_cpu(void) |
421 | { |
422 | return mon_get_cpu_sync(true); |
423 | } |
424 | |
425 | CPUArchState *mon_get_cpu_env(void) |
426 | { |
427 | CPUState *cs = mon_get_cpu(); |
428 | |
429 | return cs ? cs->env_ptr : NULL; |
430 | } |
431 | |
432 | int monitor_get_cpu_index(void) |
433 | { |
434 | CPUState *cs = mon_get_cpu_sync(false); |
435 | |
436 | return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX; |
437 | } |
438 | |
439 | static void hmp_info_registers(Monitor *mon, const QDict *qdict) |
440 | { |
441 | bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all" , false); |
442 | CPUState *cs; |
443 | |
444 | if (all_cpus) { |
445 | CPU_FOREACH(cs) { |
446 | monitor_printf(mon, "\nCPU#%d\n" , cs->cpu_index); |
447 | cpu_dump_state(cs, NULL, CPU_DUMP_FPU); |
448 | } |
449 | } else { |
450 | cs = mon_get_cpu(); |
451 | |
452 | if (!cs) { |
453 | monitor_printf(mon, "No CPU available\n" ); |
454 | return; |
455 | } |
456 | |
457 | cpu_dump_state(cs, NULL, CPU_DUMP_FPU); |
458 | } |
459 | } |
460 | |
461 | #ifdef CONFIG_TCG |
462 | static void hmp_info_jit(Monitor *mon, const QDict *qdict) |
463 | { |
464 | if (!tcg_enabled()) { |
465 | error_report("JIT information is only available with accel=tcg" ); |
466 | return; |
467 | } |
468 | |
469 | dump_exec_info(); |
470 | dump_drift_info(); |
471 | } |
472 | |
473 | static void hmp_info_opcount(Monitor *mon, const QDict *qdict) |
474 | { |
475 | dump_opcount_info(); |
476 | } |
477 | #endif |
478 | |
479 | static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) |
480 | { |
481 | int64_t max = qdict_get_try_int(qdict, "max" , 10); |
482 | bool mean = qdict_get_try_bool(qdict, "mean" , false); |
483 | bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce" , false); |
484 | enum QSPSortBy sort_by; |
485 | |
486 | sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME; |
487 | qsp_report(max, sort_by, coalesce); |
488 | } |
489 | |
490 | static void hmp_info_history(Monitor *mon, const QDict *qdict) |
491 | { |
492 | MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); |
493 | int i; |
494 | const char *str; |
495 | |
496 | if (!hmp_mon->rs) { |
497 | return; |
498 | } |
499 | i = 0; |
500 | for(;;) { |
501 | str = readline_get_history(hmp_mon->rs, i); |
502 | if (!str) { |
503 | break; |
504 | } |
505 | monitor_printf(mon, "%d: '%s'\n" , i, str); |
506 | i++; |
507 | } |
508 | } |
509 | |
510 | static void hmp_info_cpustats(Monitor *mon, const QDict *qdict) |
511 | { |
512 | CPUState *cs = mon_get_cpu(); |
513 | |
514 | if (!cs) { |
515 | monitor_printf(mon, "No CPU available\n" ); |
516 | return; |
517 | } |
518 | cpu_dump_statistics(cs, 0); |
519 | } |
520 | |
521 | static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) |
522 | { |
523 | const char *name = qdict_get_try_str(qdict, "name" ); |
524 | bool has_vcpu = qdict_haskey(qdict, "vcpu" ); |
525 | int vcpu = qdict_get_try_int(qdict, "vcpu" , 0); |
526 | TraceEventInfoList *events; |
527 | TraceEventInfoList *elem; |
528 | Error *local_err = NULL; |
529 | |
530 | if (name == NULL) { |
531 | name = "*" ; |
532 | } |
533 | if (vcpu < 0) { |
534 | monitor_printf(mon, "argument vcpu must be positive" ); |
535 | return; |
536 | } |
537 | |
538 | events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err); |
539 | if (local_err) { |
540 | error_report_err(local_err); |
541 | return; |
542 | } |
543 | |
544 | for (elem = events; elem != NULL; elem = elem->next) { |
545 | monitor_printf(mon, "%s : state %u\n" , |
546 | elem->value->name, |
547 | elem->value->state == TRACE_EVENT_STATE_ENABLED ? 1 : 0); |
548 | } |
549 | qapi_free_TraceEventInfoList(events); |
550 | } |
551 | |
552 | void qmp_client_migrate_info(const char *protocol, const char *hostname, |
553 | bool has_port, int64_t port, |
554 | bool has_tls_port, int64_t tls_port, |
555 | bool has_cert_subject, const char *cert_subject, |
556 | Error **errp) |
557 | { |
558 | if (strcmp(protocol, "spice" ) == 0) { |
559 | if (!qemu_using_spice(errp)) { |
560 | return; |
561 | } |
562 | |
563 | if (!has_port && !has_tls_port) { |
564 | error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port" ); |
565 | return; |
566 | } |
567 | |
568 | if (qemu_spice_migrate_info(hostname, |
569 | has_port ? port : -1, |
570 | has_tls_port ? tls_port : -1, |
571 | cert_subject)) { |
572 | error_setg(errp, QERR_UNDEFINED_ERROR); |
573 | return; |
574 | } |
575 | return; |
576 | } |
577 | |
578 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol" , "spice" ); |
579 | } |
580 | |
581 | static void hmp_logfile(Monitor *mon, const QDict *qdict) |
582 | { |
583 | Error *err = NULL; |
584 | |
585 | qemu_set_log_filename(qdict_get_str(qdict, "filename" ), &err); |
586 | if (err) { |
587 | error_report_err(err); |
588 | } |
589 | } |
590 | |
591 | static void hmp_log(Monitor *mon, const QDict *qdict) |
592 | { |
593 | int mask; |
594 | const char *items = qdict_get_str(qdict, "items" ); |
595 | |
596 | if (!strcmp(items, "none" )) { |
597 | mask = 0; |
598 | } else { |
599 | mask = qemu_str_to_log_mask(items); |
600 | if (!mask) { |
601 | help_cmd(mon, "log" ); |
602 | return; |
603 | } |
604 | } |
605 | qemu_set_log(mask); |
606 | } |
607 | |
608 | static void hmp_singlestep(Monitor *mon, const QDict *qdict) |
609 | { |
610 | const char *option = qdict_get_try_str(qdict, "option" ); |
611 | if (!option || !strcmp(option, "on" )) { |
612 | singlestep = 1; |
613 | } else if (!strcmp(option, "off" )) { |
614 | singlestep = 0; |
615 | } else { |
616 | monitor_printf(mon, "unexpected option %s\n" , option); |
617 | } |
618 | } |
619 | |
620 | static void hmp_gdbserver(Monitor *mon, const QDict *qdict) |
621 | { |
622 | const char *device = qdict_get_try_str(qdict, "device" ); |
623 | if (!device) |
624 | device = "tcp::" DEFAULT_GDBSTUB_PORT; |
625 | if (gdbserver_start(device) < 0) { |
626 | monitor_printf(mon, "Could not open gdbserver on device '%s'\n" , |
627 | device); |
628 | } else if (strcmp(device, "none" ) == 0) { |
629 | monitor_printf(mon, "Disabled gdbserver\n" ); |
630 | } else { |
631 | monitor_printf(mon, "Waiting for gdb connection on device '%s'\n" , |
632 | device); |
633 | } |
634 | } |
635 | |
636 | static void hmp_watchdog_action(Monitor *mon, const QDict *qdict) |
637 | { |
638 | const char *action = qdict_get_str(qdict, "action" ); |
639 | if (select_watchdog_action(action) == -1) { |
640 | monitor_printf(mon, "Unknown watchdog action '%s'\n" , action); |
641 | } |
642 | } |
643 | |
644 | static void monitor_printc(Monitor *mon, int c) |
645 | { |
646 | monitor_printf(mon, "'" ); |
647 | switch(c) { |
648 | case '\'': |
649 | monitor_printf(mon, "\\'" ); |
650 | break; |
651 | case '\\': |
652 | monitor_printf(mon, "\\\\" ); |
653 | break; |
654 | case '\n': |
655 | monitor_printf(mon, "\\n" ); |
656 | break; |
657 | case '\r': |
658 | monitor_printf(mon, "\\r" ); |
659 | break; |
660 | default: |
661 | if (c >= 32 && c <= 126) { |
662 | monitor_printf(mon, "%c" , c); |
663 | } else { |
664 | monitor_printf(mon, "\\x%02x" , c); |
665 | } |
666 | break; |
667 | } |
668 | monitor_printf(mon, "'" ); |
669 | } |
670 | |
671 | static void memory_dump(Monitor *mon, int count, int format, int wsize, |
672 | hwaddr addr, int is_physical) |
673 | { |
674 | int l, line_size, i, max_digits, len; |
675 | uint8_t buf[16]; |
676 | uint64_t v; |
677 | CPUState *cs = mon_get_cpu(); |
678 | |
679 | if (!cs && (format == 'i' || !is_physical)) { |
680 | monitor_printf(mon, "Can not dump without CPU\n" ); |
681 | return; |
682 | } |
683 | |
684 | if (format == 'i') { |
685 | monitor_disas(mon, cs, addr, count, is_physical); |
686 | return; |
687 | } |
688 | |
689 | len = wsize * count; |
690 | if (wsize == 1) |
691 | line_size = 8; |
692 | else |
693 | line_size = 16; |
694 | max_digits = 0; |
695 | |
696 | switch(format) { |
697 | case 'o': |
698 | max_digits = DIV_ROUND_UP(wsize * 8, 3); |
699 | break; |
700 | default: |
701 | case 'x': |
702 | max_digits = (wsize * 8) / 4; |
703 | break; |
704 | case 'u': |
705 | case 'd': |
706 | max_digits = DIV_ROUND_UP(wsize * 8 * 10, 33); |
707 | break; |
708 | case 'c': |
709 | wsize = 1; |
710 | break; |
711 | } |
712 | |
713 | while (len > 0) { |
714 | if (is_physical) |
715 | monitor_printf(mon, TARGET_FMT_plx ":" , addr); |
716 | else |
717 | monitor_printf(mon, TARGET_FMT_lx ":" , (target_ulong)addr); |
718 | l = len; |
719 | if (l > line_size) |
720 | l = line_size; |
721 | if (is_physical) { |
722 | AddressSpace *as = cs ? cs->as : &address_space_memory; |
723 | MemTxResult r = address_space_read(as, addr, |
724 | MEMTXATTRS_UNSPECIFIED, buf, l); |
725 | if (r != MEMTX_OK) { |
726 | monitor_printf(mon, " Cannot access memory\n" ); |
727 | break; |
728 | } |
729 | } else { |
730 | if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) { |
731 | monitor_printf(mon, " Cannot access memory\n" ); |
732 | break; |
733 | } |
734 | } |
735 | i = 0; |
736 | while (i < l) { |
737 | switch(wsize) { |
738 | default: |
739 | case 1: |
740 | v = ldub_p(buf + i); |
741 | break; |
742 | case 2: |
743 | v = lduw_p(buf + i); |
744 | break; |
745 | case 4: |
746 | v = (uint32_t)ldl_p(buf + i); |
747 | break; |
748 | case 8: |
749 | v = ldq_p(buf + i); |
750 | break; |
751 | } |
752 | monitor_printf(mon, " " ); |
753 | switch(format) { |
754 | case 'o': |
755 | monitor_printf(mon, "%#*" PRIo64, max_digits, v); |
756 | break; |
757 | case 'x': |
758 | monitor_printf(mon, "0x%0*" PRIx64, max_digits, v); |
759 | break; |
760 | case 'u': |
761 | monitor_printf(mon, "%*" PRIu64, max_digits, v); |
762 | break; |
763 | case 'd': |
764 | monitor_printf(mon, "%*" PRId64, max_digits, v); |
765 | break; |
766 | case 'c': |
767 | monitor_printc(mon, v); |
768 | break; |
769 | } |
770 | i += wsize; |
771 | } |
772 | monitor_printf(mon, "\n" ); |
773 | addr += l; |
774 | len -= l; |
775 | } |
776 | } |
777 | |
778 | static void hmp_memory_dump(Monitor *mon, const QDict *qdict) |
779 | { |
780 | int count = qdict_get_int(qdict, "count" ); |
781 | int format = qdict_get_int(qdict, "format" ); |
782 | int size = qdict_get_int(qdict, "size" ); |
783 | target_long addr = qdict_get_int(qdict, "addr" ); |
784 | |
785 | memory_dump(mon, count, format, size, addr, 0); |
786 | } |
787 | |
788 | static void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict) |
789 | { |
790 | int count = qdict_get_int(qdict, "count" ); |
791 | int format = qdict_get_int(qdict, "format" ); |
792 | int size = qdict_get_int(qdict, "size" ); |
793 | hwaddr addr = qdict_get_int(qdict, "addr" ); |
794 | |
795 | memory_dump(mon, count, format, size, addr, 1); |
796 | } |
797 | |
798 | static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp) |
799 | { |
800 | MemoryRegionSection mrs = memory_region_find(get_system_memory(), |
801 | addr, 1); |
802 | |
803 | if (!mrs.mr) { |
804 | error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, addr); |
805 | return NULL; |
806 | } |
807 | |
808 | if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { |
809 | error_setg(errp, "Memory at address 0x%" HWADDR_PRIx "is not RAM" , addr); |
810 | memory_region_unref(mrs.mr); |
811 | return NULL; |
812 | } |
813 | |
814 | *p_mr = mrs.mr; |
815 | return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); |
816 | } |
817 | |
818 | static void hmp_gpa2hva(Monitor *mon, const QDict *qdict) |
819 | { |
820 | hwaddr addr = qdict_get_int(qdict, "addr" ); |
821 | Error *local_err = NULL; |
822 | MemoryRegion *mr = NULL; |
823 | void *ptr; |
824 | |
825 | ptr = gpa2hva(&mr, addr, &local_err); |
826 | if (local_err) { |
827 | error_report_err(local_err); |
828 | return; |
829 | } |
830 | |
831 | monitor_printf(mon, "Host virtual address for 0x%" HWADDR_PRIx |
832 | " (%s) is %p\n" , |
833 | addr, mr->name, ptr); |
834 | |
835 | memory_region_unref(mr); |
836 | } |
837 | |
838 | static void hmp_gva2gpa(Monitor *mon, const QDict *qdict) |
839 | { |
840 | target_ulong addr = qdict_get_int(qdict, "addr" ); |
841 | MemTxAttrs attrs; |
842 | CPUState *cs = mon_get_cpu(); |
843 | hwaddr gpa; |
844 | |
845 | if (!cs) { |
846 | monitor_printf(mon, "No cpu\n" ); |
847 | return; |
848 | } |
849 | |
850 | gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs); |
851 | if (gpa == -1) { |
852 | monitor_printf(mon, "Unmapped\n" ); |
853 | } else { |
854 | monitor_printf(mon, "gpa: %#" HWADDR_PRIx "\n" , |
855 | gpa + (addr & ~TARGET_PAGE_MASK)); |
856 | } |
857 | } |
858 | |
859 | #ifdef CONFIG_LINUX |
860 | static uint64_t vtop(void *ptr, Error **errp) |
861 | { |
862 | uint64_t pinfo; |
863 | uint64_t ret = -1; |
864 | uintptr_t addr = (uintptr_t) ptr; |
865 | uintptr_t pagesize = getpagesize(); |
866 | off_t offset = addr / pagesize * sizeof(pinfo); |
867 | int fd; |
868 | |
869 | fd = open("/proc/self/pagemap" , O_RDONLY); |
870 | if (fd == -1) { |
871 | error_setg_errno(errp, errno, "Cannot open /proc/self/pagemap" ); |
872 | return -1; |
873 | } |
874 | |
875 | /* Force copy-on-write if necessary. */ |
876 | atomic_add((uint8_t *)ptr, 0); |
877 | |
878 | if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) { |
879 | error_setg_errno(errp, errno, "Cannot read pagemap" ); |
880 | goto out; |
881 | } |
882 | if ((pinfo & (1ull << 63)) == 0) { |
883 | error_setg(errp, "Page not present" ); |
884 | goto out; |
885 | } |
886 | ret = ((pinfo & 0x007fffffffffffffull) * pagesize) | (addr & (pagesize - 1)); |
887 | |
888 | out: |
889 | close(fd); |
890 | return ret; |
891 | } |
892 | |
893 | static void hmp_gpa2hpa(Monitor *mon, const QDict *qdict) |
894 | { |
895 | hwaddr addr = qdict_get_int(qdict, "addr" ); |
896 | Error *local_err = NULL; |
897 | MemoryRegion *mr = NULL; |
898 | void *ptr; |
899 | uint64_t physaddr; |
900 | |
901 | ptr = gpa2hva(&mr, addr, &local_err); |
902 | if (local_err) { |
903 | error_report_err(local_err); |
904 | return; |
905 | } |
906 | |
907 | physaddr = vtop(ptr, &local_err); |
908 | if (local_err) { |
909 | error_report_err(local_err); |
910 | } else { |
911 | monitor_printf(mon, "Host physical address for 0x%" HWADDR_PRIx |
912 | " (%s) is 0x%" PRIx64 "\n" , |
913 | addr, mr->name, (uint64_t) physaddr); |
914 | } |
915 | |
916 | memory_region_unref(mr); |
917 | } |
918 | #endif |
919 | |
920 | static void do_print(Monitor *mon, const QDict *qdict) |
921 | { |
922 | int format = qdict_get_int(qdict, "format" ); |
923 | hwaddr val = qdict_get_int(qdict, "val" ); |
924 | |
925 | switch(format) { |
926 | case 'o': |
927 | monitor_printf(mon, "%#" HWADDR_PRIo, val); |
928 | break; |
929 | case 'x': |
930 | monitor_printf(mon, "%#" HWADDR_PRIx, val); |
931 | break; |
932 | case 'u': |
933 | monitor_printf(mon, "%" HWADDR_PRIu, val); |
934 | break; |
935 | default: |
936 | case 'd': |
937 | monitor_printf(mon, "%" HWADDR_PRId, val); |
938 | break; |
939 | case 'c': |
940 | monitor_printc(mon, val); |
941 | break; |
942 | } |
943 | monitor_printf(mon, "\n" ); |
944 | } |
945 | |
946 | static void hmp_sum(Monitor *mon, const QDict *qdict) |
947 | { |
948 | uint32_t addr; |
949 | uint16_t sum; |
950 | uint32_t start = qdict_get_int(qdict, "start" ); |
951 | uint32_t size = qdict_get_int(qdict, "size" ); |
952 | |
953 | sum = 0; |
954 | for(addr = start; addr < (start + size); addr++) { |
955 | uint8_t val = address_space_ldub(&address_space_memory, addr, |
956 | MEMTXATTRS_UNSPECIFIED, NULL); |
957 | /* BSD sum algorithm ('sum' Unix command) */ |
958 | sum = (sum >> 1) | (sum << 15); |
959 | sum += val; |
960 | } |
961 | monitor_printf(mon, "%05d\n" , sum); |
962 | } |
963 | |
964 | static int mouse_button_state; |
965 | |
966 | static void hmp_mouse_move(Monitor *mon, const QDict *qdict) |
967 | { |
968 | int dx, dy, dz, button; |
969 | const char *dx_str = qdict_get_str(qdict, "dx_str" ); |
970 | const char *dy_str = qdict_get_str(qdict, "dy_str" ); |
971 | const char *dz_str = qdict_get_try_str(qdict, "dz_str" ); |
972 | |
973 | dx = strtol(dx_str, NULL, 0); |
974 | dy = strtol(dy_str, NULL, 0); |
975 | qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx); |
976 | qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy); |
977 | |
978 | if (dz_str) { |
979 | dz = strtol(dz_str, NULL, 0); |
980 | if (dz != 0) { |
981 | button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN; |
982 | qemu_input_queue_btn(NULL, button, true); |
983 | qemu_input_event_sync(); |
984 | qemu_input_queue_btn(NULL, button, false); |
985 | } |
986 | } |
987 | qemu_input_event_sync(); |
988 | } |
989 | |
990 | static void hmp_mouse_button(Monitor *mon, const QDict *qdict) |
991 | { |
992 | static uint32_t bmap[INPUT_BUTTON__MAX] = { |
993 | [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, |
994 | [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, |
995 | [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, |
996 | }; |
997 | int button_state = qdict_get_int(qdict, "button_state" ); |
998 | |
999 | if (mouse_button_state == button_state) { |
1000 | return; |
1001 | } |
1002 | qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state); |
1003 | qemu_input_event_sync(); |
1004 | mouse_button_state = button_state; |
1005 | } |
1006 | |
1007 | static void hmp_ioport_read(Monitor *mon, const QDict *qdict) |
1008 | { |
1009 | int size = qdict_get_int(qdict, "size" ); |
1010 | int addr = qdict_get_int(qdict, "addr" ); |
1011 | int has_index = qdict_haskey(qdict, "index" ); |
1012 | uint32_t val; |
1013 | int suffix; |
1014 | |
1015 | if (has_index) { |
1016 | int index = qdict_get_int(qdict, "index" ); |
1017 | cpu_outb(addr & IOPORTS_MASK, index & 0xff); |
1018 | addr++; |
1019 | } |
1020 | addr &= 0xffff; |
1021 | |
1022 | switch(size) { |
1023 | default: |
1024 | case 1: |
1025 | val = cpu_inb(addr); |
1026 | suffix = 'b'; |
1027 | break; |
1028 | case 2: |
1029 | val = cpu_inw(addr); |
1030 | suffix = 'w'; |
1031 | break; |
1032 | case 4: |
1033 | val = cpu_inl(addr); |
1034 | suffix = 'l'; |
1035 | break; |
1036 | } |
1037 | monitor_printf(mon, "port%c[0x%04x] = %#0*x\n" , |
1038 | suffix, addr, size * 2, val); |
1039 | } |
1040 | |
1041 | static void hmp_ioport_write(Monitor *mon, const QDict *qdict) |
1042 | { |
1043 | int size = qdict_get_int(qdict, "size" ); |
1044 | int addr = qdict_get_int(qdict, "addr" ); |
1045 | int val = qdict_get_int(qdict, "val" ); |
1046 | |
1047 | addr &= IOPORTS_MASK; |
1048 | |
1049 | switch (size) { |
1050 | default: |
1051 | case 1: |
1052 | cpu_outb(addr, val); |
1053 | break; |
1054 | case 2: |
1055 | cpu_outw(addr, val); |
1056 | break; |
1057 | case 4: |
1058 | cpu_outl(addr, val); |
1059 | break; |
1060 | } |
1061 | } |
1062 | |
1063 | static void hmp_boot_set(Monitor *mon, const QDict *qdict) |
1064 | { |
1065 | Error *local_err = NULL; |
1066 | const char *bootdevice = qdict_get_str(qdict, "bootdevice" ); |
1067 | |
1068 | qemu_boot_set(bootdevice, &local_err); |
1069 | if (local_err) { |
1070 | error_report_err(local_err); |
1071 | } else { |
1072 | monitor_printf(mon, "boot device list now set to %s\n" , bootdevice); |
1073 | } |
1074 | } |
1075 | |
1076 | static void hmp_info_mtree(Monitor *mon, const QDict *qdict) |
1077 | { |
1078 | bool flatview = qdict_get_try_bool(qdict, "flatview" , false); |
1079 | bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree" , false); |
1080 | bool owner = qdict_get_try_bool(qdict, "owner" , false); |
1081 | |
1082 | mtree_info(flatview, dispatch_tree, owner); |
1083 | } |
1084 | |
1085 | #ifdef CONFIG_PROFILER |
1086 | |
1087 | int64_t dev_time; |
1088 | |
1089 | static void hmp_info_profile(Monitor *mon, const QDict *qdict) |
1090 | { |
1091 | static int64_t last_cpu_exec_time; |
1092 | int64_t cpu_exec_time; |
1093 | int64_t delta; |
1094 | |
1095 | cpu_exec_time = tcg_cpu_exec_time(); |
1096 | delta = cpu_exec_time - last_cpu_exec_time; |
1097 | |
1098 | monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n" , |
1099 | dev_time, dev_time / (double)NANOSECONDS_PER_SECOND); |
1100 | monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n" , |
1101 | delta, delta / (double)NANOSECONDS_PER_SECOND); |
1102 | last_cpu_exec_time = cpu_exec_time; |
1103 | dev_time = 0; |
1104 | } |
1105 | #else |
1106 | static void hmp_info_profile(Monitor *mon, const QDict *qdict) |
1107 | { |
1108 | monitor_printf(mon, "Internal profiler not compiled\n" ); |
1109 | } |
1110 | #endif |
1111 | |
1112 | /* Capture support */ |
1113 | static QLIST_HEAD (capture_list_head, CaptureState) capture_head; |
1114 | |
1115 | static void hmp_info_capture(Monitor *mon, const QDict *qdict) |
1116 | { |
1117 | int i; |
1118 | CaptureState *s; |
1119 | |
1120 | for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { |
1121 | monitor_printf(mon, "[%d]: " , i); |
1122 | s->ops.info (s->opaque); |
1123 | } |
1124 | } |
1125 | |
1126 | static void hmp_stopcapture(Monitor *mon, const QDict *qdict) |
1127 | { |
1128 | int i; |
1129 | int n = qdict_get_int(qdict, "n" ); |
1130 | CaptureState *s; |
1131 | |
1132 | for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { |
1133 | if (i == n) { |
1134 | s->ops.destroy (s->opaque); |
1135 | QLIST_REMOVE (s, entries); |
1136 | g_free (s); |
1137 | return; |
1138 | } |
1139 | } |
1140 | } |
1141 | |
1142 | static void hmp_wavcapture(Monitor *mon, const QDict *qdict) |
1143 | { |
1144 | const char *path = qdict_get_str(qdict, "path" ); |
1145 | int freq = qdict_get_try_int(qdict, "freq" , 44100); |
1146 | int bits = qdict_get_try_int(qdict, "bits" , 16); |
1147 | int nchannels = qdict_get_try_int(qdict, "nchannels" , 2); |
1148 | const char *audiodev = qdict_get_str(qdict, "audiodev" ); |
1149 | CaptureState *s; |
1150 | AudioState *as = audio_state_by_name(audiodev); |
1151 | |
1152 | if (!as) { |
1153 | monitor_printf(mon, "Audiodev '%s' not found\n" , audiodev); |
1154 | return; |
1155 | } |
1156 | |
1157 | s = g_malloc0 (sizeof (*s)); |
1158 | |
1159 | if (wav_start_capture(as, s, path, freq, bits, nchannels)) { |
1160 | monitor_printf(mon, "Failed to add wave capture\n" ); |
1161 | g_free (s); |
1162 | return; |
1163 | } |
1164 | QLIST_INSERT_HEAD (&capture_head, s, entries); |
1165 | } |
1166 | |
1167 | static QAuthZList *find_auth(Monitor *mon, const char *name) |
1168 | { |
1169 | Object *obj; |
1170 | Object *container; |
1171 | |
1172 | container = object_get_objects_root(); |
1173 | obj = object_resolve_path_component(container, name); |
1174 | if (!obj) { |
1175 | monitor_printf(mon, "acl: unknown list '%s'\n" , name); |
1176 | return NULL; |
1177 | } |
1178 | |
1179 | return QAUTHZ_LIST(obj); |
1180 | } |
1181 | |
1182 | static bool warn_acl; |
1183 | static void hmp_warn_acl(void) |
1184 | { |
1185 | if (warn_acl) { |
1186 | return; |
1187 | } |
1188 | error_report("The acl_show, acl_reset, acl_policy, acl_add, acl_remove " |
1189 | "commands are deprecated with no replacement. Authorization " |
1190 | "for VNC should be performed using the pluggable QAuthZ " |
1191 | "objects" ); |
1192 | warn_acl = true; |
1193 | } |
1194 | |
1195 | static void hmp_acl_show(Monitor *mon, const QDict *qdict) |
1196 | { |
1197 | const char *aclname = qdict_get_str(qdict, "aclname" ); |
1198 | QAuthZList *auth = find_auth(mon, aclname); |
1199 | QAuthZListRuleList *rules; |
1200 | size_t i = 0; |
1201 | |
1202 | hmp_warn_acl(); |
1203 | |
1204 | if (!auth) { |
1205 | return; |
1206 | } |
1207 | |
1208 | monitor_printf(mon, "policy: %s\n" , |
1209 | QAuthZListPolicy_str(auth->policy)); |
1210 | |
1211 | rules = auth->rules; |
1212 | while (rules) { |
1213 | QAuthZListRule *rule = rules->value; |
1214 | i++; |
1215 | monitor_printf(mon, "%zu: %s %s\n" , i, |
1216 | QAuthZListPolicy_str(rule->policy), |
1217 | rule->match); |
1218 | rules = rules->next; |
1219 | } |
1220 | } |
1221 | |
1222 | static void hmp_acl_reset(Monitor *mon, const QDict *qdict) |
1223 | { |
1224 | const char *aclname = qdict_get_str(qdict, "aclname" ); |
1225 | QAuthZList *auth = find_auth(mon, aclname); |
1226 | |
1227 | hmp_warn_acl(); |
1228 | |
1229 | if (!auth) { |
1230 | return; |
1231 | } |
1232 | |
1233 | auth->policy = QAUTHZ_LIST_POLICY_DENY; |
1234 | qapi_free_QAuthZListRuleList(auth->rules); |
1235 | auth->rules = NULL; |
1236 | monitor_printf(mon, "acl: removed all rules\n" ); |
1237 | } |
1238 | |
1239 | static void hmp_acl_policy(Monitor *mon, const QDict *qdict) |
1240 | { |
1241 | const char *aclname = qdict_get_str(qdict, "aclname" ); |
1242 | const char *policy = qdict_get_str(qdict, "policy" ); |
1243 | QAuthZList *auth = find_auth(mon, aclname); |
1244 | int val; |
1245 | Error *err = NULL; |
1246 | |
1247 | hmp_warn_acl(); |
1248 | |
1249 | if (!auth) { |
1250 | return; |
1251 | } |
1252 | |
1253 | val = qapi_enum_parse(&QAuthZListPolicy_lookup, |
1254 | policy, |
1255 | QAUTHZ_LIST_POLICY_DENY, |
1256 | &err); |
1257 | if (err) { |
1258 | error_free(err); |
1259 | monitor_printf(mon, "acl: unknown policy '%s', " |
1260 | "expected 'deny' or 'allow'\n" , policy); |
1261 | } else { |
1262 | auth->policy = val; |
1263 | if (auth->policy == QAUTHZ_LIST_POLICY_ALLOW) { |
1264 | monitor_printf(mon, "acl: policy set to 'allow'\n" ); |
1265 | } else { |
1266 | monitor_printf(mon, "acl: policy set to 'deny'\n" ); |
1267 | } |
1268 | } |
1269 | } |
1270 | |
1271 | static QAuthZListFormat hmp_acl_get_format(const char *match) |
1272 | { |
1273 | if (strchr(match, '*')) { |
1274 | return QAUTHZ_LIST_FORMAT_GLOB; |
1275 | } else { |
1276 | return QAUTHZ_LIST_FORMAT_EXACT; |
1277 | } |
1278 | } |
1279 | |
1280 | static void hmp_acl_add(Monitor *mon, const QDict *qdict) |
1281 | { |
1282 | const char *aclname = qdict_get_str(qdict, "aclname" ); |
1283 | const char *match = qdict_get_str(qdict, "match" ); |
1284 | const char *policystr = qdict_get_str(qdict, "policy" ); |
1285 | int has_index = qdict_haskey(qdict, "index" ); |
1286 | int index = qdict_get_try_int(qdict, "index" , -1); |
1287 | QAuthZList *auth = find_auth(mon, aclname); |
1288 | Error *err = NULL; |
1289 | QAuthZListPolicy policy; |
1290 | QAuthZListFormat format; |
1291 | size_t i = 0; |
1292 | |
1293 | hmp_warn_acl(); |
1294 | |
1295 | if (!auth) { |
1296 | return; |
1297 | } |
1298 | |
1299 | policy = qapi_enum_parse(&QAuthZListPolicy_lookup, |
1300 | policystr, |
1301 | QAUTHZ_LIST_POLICY_DENY, |
1302 | &err); |
1303 | if (err) { |
1304 | error_free(err); |
1305 | monitor_printf(mon, "acl: unknown policy '%s', " |
1306 | "expected 'deny' or 'allow'\n" , policystr); |
1307 | return; |
1308 | } |
1309 | |
1310 | format = hmp_acl_get_format(match); |
1311 | |
1312 | if (has_index && index == 0) { |
1313 | monitor_printf(mon, "acl: unable to add acl entry\n" ); |
1314 | return; |
1315 | } |
1316 | |
1317 | if (has_index) { |
1318 | i = qauthz_list_insert_rule(auth, match, policy, |
1319 | format, index - 1, &err); |
1320 | } else { |
1321 | i = qauthz_list_append_rule(auth, match, policy, |
1322 | format, &err); |
1323 | } |
1324 | if (err) { |
1325 | monitor_printf(mon, "acl: unable to add rule: %s" , |
1326 | error_get_pretty(err)); |
1327 | error_free(err); |
1328 | } else { |
1329 | monitor_printf(mon, "acl: added rule at position %zu\n" , i + 1); |
1330 | } |
1331 | } |
1332 | |
1333 | static void hmp_acl_remove(Monitor *mon, const QDict *qdict) |
1334 | { |
1335 | const char *aclname = qdict_get_str(qdict, "aclname" ); |
1336 | const char *match = qdict_get_str(qdict, "match" ); |
1337 | QAuthZList *auth = find_auth(mon, aclname); |
1338 | ssize_t i = 0; |
1339 | |
1340 | hmp_warn_acl(); |
1341 | |
1342 | if (!auth) { |
1343 | return; |
1344 | } |
1345 | |
1346 | i = qauthz_list_delete_rule(auth, match); |
1347 | if (i >= 0) { |
1348 | monitor_printf(mon, "acl: removed rule at position %zu\n" , i + 1); |
1349 | } else { |
1350 | monitor_printf(mon, "acl: no matching acl entry\n" ); |
1351 | } |
1352 | } |
1353 | |
1354 | void qmp_getfd(const char *fdname, Error **errp) |
1355 | { |
1356 | mon_fd_t *monfd; |
1357 | int fd, tmp_fd; |
1358 | |
1359 | fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); |
1360 | if (fd == -1) { |
1361 | error_setg(errp, QERR_FD_NOT_SUPPLIED); |
1362 | return; |
1363 | } |
1364 | |
1365 | if (qemu_isdigit(fdname[0])) { |
1366 | close(fd); |
1367 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname" , |
1368 | "a name not starting with a digit" ); |
1369 | return; |
1370 | } |
1371 | |
1372 | qemu_mutex_lock(&cur_mon->mon_lock); |
1373 | QLIST_FOREACH(monfd, &cur_mon->fds, next) { |
1374 | if (strcmp(monfd->name, fdname) != 0) { |
1375 | continue; |
1376 | } |
1377 | |
1378 | tmp_fd = monfd->fd; |
1379 | monfd->fd = fd; |
1380 | qemu_mutex_unlock(&cur_mon->mon_lock); |
1381 | /* Make sure close() is outside critical section */ |
1382 | close(tmp_fd); |
1383 | return; |
1384 | } |
1385 | |
1386 | monfd = g_malloc0(sizeof(mon_fd_t)); |
1387 | monfd->name = g_strdup(fdname); |
1388 | monfd->fd = fd; |
1389 | |
1390 | QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next); |
1391 | qemu_mutex_unlock(&cur_mon->mon_lock); |
1392 | } |
1393 | |
1394 | void qmp_closefd(const char *fdname, Error **errp) |
1395 | { |
1396 | mon_fd_t *monfd; |
1397 | int tmp_fd; |
1398 | |
1399 | qemu_mutex_lock(&cur_mon->mon_lock); |
1400 | QLIST_FOREACH(monfd, &cur_mon->fds, next) { |
1401 | if (strcmp(monfd->name, fdname) != 0) { |
1402 | continue; |
1403 | } |
1404 | |
1405 | QLIST_REMOVE(monfd, next); |
1406 | tmp_fd = monfd->fd; |
1407 | g_free(monfd->name); |
1408 | g_free(monfd); |
1409 | qemu_mutex_unlock(&cur_mon->mon_lock); |
1410 | /* Make sure close() is outside critical section */ |
1411 | close(tmp_fd); |
1412 | return; |
1413 | } |
1414 | |
1415 | qemu_mutex_unlock(&cur_mon->mon_lock); |
1416 | error_setg(errp, QERR_FD_NOT_FOUND, fdname); |
1417 | } |
1418 | |
1419 | int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) |
1420 | { |
1421 | mon_fd_t *monfd; |
1422 | |
1423 | qemu_mutex_lock(&mon->mon_lock); |
1424 | QLIST_FOREACH(monfd, &mon->fds, next) { |
1425 | int fd; |
1426 | |
1427 | if (strcmp(monfd->name, fdname) != 0) { |
1428 | continue; |
1429 | } |
1430 | |
1431 | fd = monfd->fd; |
1432 | |
1433 | /* caller takes ownership of fd */ |
1434 | QLIST_REMOVE(monfd, next); |
1435 | g_free(monfd->name); |
1436 | g_free(monfd); |
1437 | qemu_mutex_unlock(&mon->mon_lock); |
1438 | |
1439 | return fd; |
1440 | } |
1441 | |
1442 | qemu_mutex_unlock(&mon->mon_lock); |
1443 | error_setg(errp, "File descriptor named '%s' has not been found" , fdname); |
1444 | return -1; |
1445 | } |
1446 | |
1447 | static void monitor_fdset_cleanup(MonFdset *mon_fdset) |
1448 | { |
1449 | MonFdsetFd *mon_fdset_fd; |
1450 | MonFdsetFd *mon_fdset_fd_next; |
1451 | |
1452 | QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) { |
1453 | if ((mon_fdset_fd->removed || |
1454 | (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) && |
1455 | runstate_is_running()) { |
1456 | close(mon_fdset_fd->fd); |
1457 | g_free(mon_fdset_fd->opaque); |
1458 | QLIST_REMOVE(mon_fdset_fd, next); |
1459 | g_free(mon_fdset_fd); |
1460 | } |
1461 | } |
1462 | |
1463 | if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { |
1464 | QLIST_REMOVE(mon_fdset, next); |
1465 | g_free(mon_fdset); |
1466 | } |
1467 | } |
1468 | |
1469 | void monitor_fdsets_cleanup(void) |
1470 | { |
1471 | MonFdset *mon_fdset; |
1472 | MonFdset *mon_fdset_next; |
1473 | |
1474 | qemu_mutex_lock(&mon_fdsets_lock); |
1475 | QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { |
1476 | monitor_fdset_cleanup(mon_fdset); |
1477 | } |
1478 | qemu_mutex_unlock(&mon_fdsets_lock); |
1479 | } |
1480 | |
1481 | AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque, |
1482 | const char *opaque, Error **errp) |
1483 | { |
1484 | int fd; |
1485 | Monitor *mon = cur_mon; |
1486 | AddfdInfo *fdinfo; |
1487 | |
1488 | fd = qemu_chr_fe_get_msgfd(&mon->chr); |
1489 | if (fd == -1) { |
1490 | error_setg(errp, QERR_FD_NOT_SUPPLIED); |
1491 | goto error; |
1492 | } |
1493 | |
1494 | fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, |
1495 | has_opaque, opaque, errp); |
1496 | if (fdinfo) { |
1497 | return fdinfo; |
1498 | } |
1499 | |
1500 | error: |
1501 | if (fd != -1) { |
1502 | close(fd); |
1503 | } |
1504 | return NULL; |
1505 | } |
1506 | |
1507 | void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) |
1508 | { |
1509 | MonFdset *mon_fdset; |
1510 | MonFdsetFd *mon_fdset_fd; |
1511 | char fd_str[60]; |
1512 | |
1513 | qemu_mutex_lock(&mon_fdsets_lock); |
1514 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1515 | if (mon_fdset->id != fdset_id) { |
1516 | continue; |
1517 | } |
1518 | QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { |
1519 | if (has_fd) { |
1520 | if (mon_fdset_fd->fd != fd) { |
1521 | continue; |
1522 | } |
1523 | mon_fdset_fd->removed = true; |
1524 | break; |
1525 | } else { |
1526 | mon_fdset_fd->removed = true; |
1527 | } |
1528 | } |
1529 | if (has_fd && !mon_fdset_fd) { |
1530 | goto error; |
1531 | } |
1532 | monitor_fdset_cleanup(mon_fdset); |
1533 | qemu_mutex_unlock(&mon_fdsets_lock); |
1534 | return; |
1535 | } |
1536 | |
1537 | error: |
1538 | qemu_mutex_unlock(&mon_fdsets_lock); |
1539 | if (has_fd) { |
1540 | snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, |
1541 | fdset_id, fd); |
1542 | } else { |
1543 | snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); |
1544 | } |
1545 | error_setg(errp, QERR_FD_NOT_FOUND, fd_str); |
1546 | } |
1547 | |
1548 | FdsetInfoList *qmp_query_fdsets(Error **errp) |
1549 | { |
1550 | MonFdset *mon_fdset; |
1551 | MonFdsetFd *mon_fdset_fd; |
1552 | FdsetInfoList *fdset_list = NULL; |
1553 | |
1554 | qemu_mutex_lock(&mon_fdsets_lock); |
1555 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1556 | FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info)); |
1557 | FdsetFdInfoList *fdsetfd_list = NULL; |
1558 | |
1559 | fdset_info->value = g_malloc0(sizeof(*fdset_info->value)); |
1560 | fdset_info->value->fdset_id = mon_fdset->id; |
1561 | |
1562 | QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { |
1563 | FdsetFdInfoList *fdsetfd_info; |
1564 | |
1565 | fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); |
1566 | fdsetfd_info->value = g_malloc0(sizeof(*fdsetfd_info->value)); |
1567 | fdsetfd_info->value->fd = mon_fdset_fd->fd; |
1568 | if (mon_fdset_fd->opaque) { |
1569 | fdsetfd_info->value->has_opaque = true; |
1570 | fdsetfd_info->value->opaque = g_strdup(mon_fdset_fd->opaque); |
1571 | } else { |
1572 | fdsetfd_info->value->has_opaque = false; |
1573 | } |
1574 | |
1575 | fdsetfd_info->next = fdsetfd_list; |
1576 | fdsetfd_list = fdsetfd_info; |
1577 | } |
1578 | |
1579 | fdset_info->value->fds = fdsetfd_list; |
1580 | |
1581 | fdset_info->next = fdset_list; |
1582 | fdset_list = fdset_info; |
1583 | } |
1584 | qemu_mutex_unlock(&mon_fdsets_lock); |
1585 | |
1586 | return fdset_list; |
1587 | } |
1588 | |
1589 | AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, |
1590 | bool has_opaque, const char *opaque, |
1591 | Error **errp) |
1592 | { |
1593 | MonFdset *mon_fdset = NULL; |
1594 | MonFdsetFd *mon_fdset_fd; |
1595 | AddfdInfo *fdinfo; |
1596 | |
1597 | qemu_mutex_lock(&mon_fdsets_lock); |
1598 | if (has_fdset_id) { |
1599 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1600 | /* Break if match found or match impossible due to ordering by ID */ |
1601 | if (fdset_id <= mon_fdset->id) { |
1602 | if (fdset_id < mon_fdset->id) { |
1603 | mon_fdset = NULL; |
1604 | } |
1605 | break; |
1606 | } |
1607 | } |
1608 | } |
1609 | |
1610 | if (mon_fdset == NULL) { |
1611 | int64_t fdset_id_prev = -1; |
1612 | MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); |
1613 | |
1614 | if (has_fdset_id) { |
1615 | if (fdset_id < 0) { |
1616 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id" , |
1617 | "a non-negative value" ); |
1618 | qemu_mutex_unlock(&mon_fdsets_lock); |
1619 | return NULL; |
1620 | } |
1621 | /* Use specified fdset ID */ |
1622 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1623 | mon_fdset_cur = mon_fdset; |
1624 | if (fdset_id < mon_fdset_cur->id) { |
1625 | break; |
1626 | } |
1627 | } |
1628 | } else { |
1629 | /* Use first available fdset ID */ |
1630 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1631 | mon_fdset_cur = mon_fdset; |
1632 | if (fdset_id_prev == mon_fdset_cur->id - 1) { |
1633 | fdset_id_prev = mon_fdset_cur->id; |
1634 | continue; |
1635 | } |
1636 | break; |
1637 | } |
1638 | } |
1639 | |
1640 | mon_fdset = g_malloc0(sizeof(*mon_fdset)); |
1641 | if (has_fdset_id) { |
1642 | mon_fdset->id = fdset_id; |
1643 | } else { |
1644 | mon_fdset->id = fdset_id_prev + 1; |
1645 | } |
1646 | |
1647 | /* The fdset list is ordered by fdset ID */ |
1648 | if (!mon_fdset_cur) { |
1649 | QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); |
1650 | } else if (mon_fdset->id < mon_fdset_cur->id) { |
1651 | QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); |
1652 | } else { |
1653 | QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); |
1654 | } |
1655 | } |
1656 | |
1657 | mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); |
1658 | mon_fdset_fd->fd = fd; |
1659 | mon_fdset_fd->removed = false; |
1660 | if (has_opaque) { |
1661 | mon_fdset_fd->opaque = g_strdup(opaque); |
1662 | } |
1663 | QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); |
1664 | |
1665 | fdinfo = g_malloc0(sizeof(*fdinfo)); |
1666 | fdinfo->fdset_id = mon_fdset->id; |
1667 | fdinfo->fd = mon_fdset_fd->fd; |
1668 | |
1669 | qemu_mutex_unlock(&mon_fdsets_lock); |
1670 | return fdinfo; |
1671 | } |
1672 | |
1673 | int monitor_fdset_get_fd(int64_t fdset_id, int flags) |
1674 | { |
1675 | #ifdef _WIN32 |
1676 | return -ENOENT; |
1677 | #else |
1678 | MonFdset *mon_fdset; |
1679 | MonFdsetFd *mon_fdset_fd; |
1680 | int mon_fd_flags; |
1681 | int ret; |
1682 | |
1683 | qemu_mutex_lock(&mon_fdsets_lock); |
1684 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1685 | if (mon_fdset->id != fdset_id) { |
1686 | continue; |
1687 | } |
1688 | QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { |
1689 | mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); |
1690 | if (mon_fd_flags == -1) { |
1691 | ret = -errno; |
1692 | goto out; |
1693 | } |
1694 | |
1695 | if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { |
1696 | ret = mon_fdset_fd->fd; |
1697 | goto out; |
1698 | } |
1699 | } |
1700 | ret = -EACCES; |
1701 | goto out; |
1702 | } |
1703 | ret = -ENOENT; |
1704 | |
1705 | out: |
1706 | qemu_mutex_unlock(&mon_fdsets_lock); |
1707 | return ret; |
1708 | #endif |
1709 | } |
1710 | |
1711 | int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) |
1712 | { |
1713 | MonFdset *mon_fdset; |
1714 | MonFdsetFd *mon_fdset_fd_dup; |
1715 | |
1716 | qemu_mutex_lock(&mon_fdsets_lock); |
1717 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1718 | if (mon_fdset->id != fdset_id) { |
1719 | continue; |
1720 | } |
1721 | QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { |
1722 | if (mon_fdset_fd_dup->fd == dup_fd) { |
1723 | goto err; |
1724 | } |
1725 | } |
1726 | mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); |
1727 | mon_fdset_fd_dup->fd = dup_fd; |
1728 | QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); |
1729 | qemu_mutex_unlock(&mon_fdsets_lock); |
1730 | return 0; |
1731 | } |
1732 | |
1733 | err: |
1734 | qemu_mutex_unlock(&mon_fdsets_lock); |
1735 | return -1; |
1736 | } |
1737 | |
1738 | static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) |
1739 | { |
1740 | MonFdset *mon_fdset; |
1741 | MonFdsetFd *mon_fdset_fd_dup; |
1742 | |
1743 | qemu_mutex_lock(&mon_fdsets_lock); |
1744 | QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { |
1745 | QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { |
1746 | if (mon_fdset_fd_dup->fd == dup_fd) { |
1747 | if (remove) { |
1748 | QLIST_REMOVE(mon_fdset_fd_dup, next); |
1749 | if (QLIST_EMPTY(&mon_fdset->dup_fds)) { |
1750 | monitor_fdset_cleanup(mon_fdset); |
1751 | } |
1752 | goto err; |
1753 | } else { |
1754 | qemu_mutex_unlock(&mon_fdsets_lock); |
1755 | return mon_fdset->id; |
1756 | } |
1757 | } |
1758 | } |
1759 | } |
1760 | |
1761 | err: |
1762 | qemu_mutex_unlock(&mon_fdsets_lock); |
1763 | return -1; |
1764 | } |
1765 | |
1766 | int64_t monitor_fdset_dup_fd_find(int dup_fd) |
1767 | { |
1768 | return monitor_fdset_dup_fd_find_remove(dup_fd, false); |
1769 | } |
1770 | |
1771 | void monitor_fdset_dup_fd_remove(int dup_fd) |
1772 | { |
1773 | monitor_fdset_dup_fd_find_remove(dup_fd, true); |
1774 | } |
1775 | |
1776 | int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) |
1777 | { |
1778 | int fd; |
1779 | Error *local_err = NULL; |
1780 | |
1781 | if (!qemu_isdigit(fdname[0]) && mon) { |
1782 | fd = monitor_get_fd(mon, fdname, &local_err); |
1783 | } else { |
1784 | fd = qemu_parse_fd(fdname); |
1785 | if (fd == -1) { |
1786 | error_setg(&local_err, "Invalid file descriptor number '%s'" , |
1787 | fdname); |
1788 | } |
1789 | } |
1790 | if (local_err) { |
1791 | error_propagate(errp, local_err); |
1792 | assert(fd == -1); |
1793 | } else { |
1794 | assert(fd != -1); |
1795 | } |
1796 | |
1797 | return fd; |
1798 | } |
1799 | |
1800 | /* Please update hmp-commands.hx when adding or changing commands */ |
1801 | static HMPCommand hmp_info_cmds[] = { |
1802 | #include "hmp-commands-info.h" |
1803 | { NULL, NULL, }, |
1804 | }; |
1805 | |
1806 | /* hmp_cmds and hmp_info_cmds would be sorted at runtime */ |
1807 | HMPCommand hmp_cmds[] = { |
1808 | #include "hmp-commands.h" |
1809 | { NULL, NULL, }, |
1810 | }; |
1811 | |
1812 | /* |
1813 | * Set @pval to the value in the register identified by @name. |
1814 | * return 0 if OK, -1 if not found |
1815 | */ |
1816 | int get_monitor_def(int64_t *pval, const char *name) |
1817 | { |
1818 | const MonitorDef *md = target_monitor_defs(); |
1819 | CPUState *cs = mon_get_cpu(); |
1820 | void *ptr; |
1821 | uint64_t tmp = 0; |
1822 | int ret; |
1823 | |
1824 | if (cs == NULL || md == NULL) { |
1825 | return -1; |
1826 | } |
1827 | |
1828 | for(; md->name != NULL; md++) { |
1829 | if (hmp_compare_cmd(name, md->name)) { |
1830 | if (md->get_value) { |
1831 | *pval = md->get_value(md, md->offset); |
1832 | } else { |
1833 | CPUArchState *env = mon_get_cpu_env(); |
1834 | ptr = (uint8_t *)env + md->offset; |
1835 | switch(md->type) { |
1836 | case MD_I32: |
1837 | *pval = *(int32_t *)ptr; |
1838 | break; |
1839 | case MD_TLONG: |
1840 | *pval = *(target_long *)ptr; |
1841 | break; |
1842 | default: |
1843 | *pval = 0; |
1844 | break; |
1845 | } |
1846 | } |
1847 | return 0; |
1848 | } |
1849 | } |
1850 | |
1851 | ret = target_get_monitor_def(cs, name, &tmp); |
1852 | if (!ret) { |
1853 | *pval = (target_long) tmp; |
1854 | } |
1855 | |
1856 | return ret; |
1857 | } |
1858 | |
1859 | static void add_completion_option(ReadLineState *rs, const char *str, |
1860 | const char *option) |
1861 | { |
1862 | if (!str || !option) { |
1863 | return; |
1864 | } |
1865 | if (!strncmp(option, str, strlen(str))) { |
1866 | readline_add_completion(rs, option); |
1867 | } |
1868 | } |
1869 | |
1870 | void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str) |
1871 | { |
1872 | size_t len; |
1873 | ChardevBackendInfoList *list, *start; |
1874 | |
1875 | if (nb_args != 2) { |
1876 | return; |
1877 | } |
1878 | len = strlen(str); |
1879 | readline_set_completion_index(rs, len); |
1880 | |
1881 | start = list = qmp_query_chardev_backends(NULL); |
1882 | while (list) { |
1883 | const char *chr_name = list->value->name; |
1884 | |
1885 | if (!strncmp(chr_name, str, len)) { |
1886 | readline_add_completion(rs, chr_name); |
1887 | } |
1888 | list = list->next; |
1889 | } |
1890 | qapi_free_ChardevBackendInfoList(start); |
1891 | } |
1892 | |
1893 | void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) |
1894 | { |
1895 | size_t len; |
1896 | int i; |
1897 | |
1898 | if (nb_args != 2) { |
1899 | return; |
1900 | } |
1901 | len = strlen(str); |
1902 | readline_set_completion_index(rs, len); |
1903 | for (i = 0; i < NET_CLIENT_DRIVER__MAX; i++) { |
1904 | add_completion_option(rs, str, NetClientDriver_str(i)); |
1905 | } |
1906 | } |
1907 | |
1908 | void device_add_completion(ReadLineState *rs, int nb_args, const char *str) |
1909 | { |
1910 | GSList *list, *elt; |
1911 | size_t len; |
1912 | |
1913 | if (nb_args != 2) { |
1914 | return; |
1915 | } |
1916 | |
1917 | len = strlen(str); |
1918 | readline_set_completion_index(rs, len); |
1919 | list = elt = object_class_get_list(TYPE_DEVICE, false); |
1920 | while (elt) { |
1921 | const char *name; |
1922 | DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data, |
1923 | TYPE_DEVICE); |
1924 | name = object_class_get_name(OBJECT_CLASS(dc)); |
1925 | |
1926 | if (dc->user_creatable |
1927 | && !strncmp(name, str, len)) { |
1928 | readline_add_completion(rs, name); |
1929 | } |
1930 | elt = elt->next; |
1931 | } |
1932 | g_slist_free(list); |
1933 | } |
1934 | |
1935 | void object_add_completion(ReadLineState *rs, int nb_args, const char *str) |
1936 | { |
1937 | GSList *list, *elt; |
1938 | size_t len; |
1939 | |
1940 | if (nb_args != 2) { |
1941 | return; |
1942 | } |
1943 | |
1944 | len = strlen(str); |
1945 | readline_set_completion_index(rs, len); |
1946 | list = elt = object_class_get_list(TYPE_USER_CREATABLE, false); |
1947 | while (elt) { |
1948 | const char *name; |
1949 | |
1950 | name = object_class_get_name(OBJECT_CLASS(elt->data)); |
1951 | if (!strncmp(name, str, len) && strcmp(name, TYPE_USER_CREATABLE)) { |
1952 | readline_add_completion(rs, name); |
1953 | } |
1954 | elt = elt->next; |
1955 | } |
1956 | g_slist_free(list); |
1957 | } |
1958 | |
1959 | static void peripheral_device_del_completion(ReadLineState *rs, |
1960 | const char *str, size_t len) |
1961 | { |
1962 | Object *peripheral = container_get(qdev_get_machine(), "/peripheral" ); |
1963 | GSList *list, *item; |
1964 | |
1965 | list = qdev_build_hotpluggable_device_list(peripheral); |
1966 | if (!list) { |
1967 | return; |
1968 | } |
1969 | |
1970 | for (item = list; item; item = g_slist_next(item)) { |
1971 | DeviceState *dev = item->data; |
1972 | |
1973 | if (dev->id && !strncmp(str, dev->id, len)) { |
1974 | readline_add_completion(rs, dev->id); |
1975 | } |
1976 | } |
1977 | |
1978 | g_slist_free(list); |
1979 | } |
1980 | |
1981 | void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str) |
1982 | { |
1983 | size_t len; |
1984 | ChardevInfoList *list, *start; |
1985 | |
1986 | if (nb_args != 2) { |
1987 | return; |
1988 | } |
1989 | len = strlen(str); |
1990 | readline_set_completion_index(rs, len); |
1991 | |
1992 | start = list = qmp_query_chardev(NULL); |
1993 | while (list) { |
1994 | ChardevInfo *chr = list->value; |
1995 | |
1996 | if (!strncmp(chr->label, str, len)) { |
1997 | readline_add_completion(rs, chr->label); |
1998 | } |
1999 | list = list->next; |
2000 | } |
2001 | qapi_free_ChardevInfoList(start); |
2002 | } |
2003 | |
2004 | static void ringbuf_completion(ReadLineState *rs, const char *str) |
2005 | { |
2006 | size_t len; |
2007 | ChardevInfoList *list, *start; |
2008 | |
2009 | len = strlen(str); |
2010 | readline_set_completion_index(rs, len); |
2011 | |
2012 | start = list = qmp_query_chardev(NULL); |
2013 | while (list) { |
2014 | ChardevInfo *chr_info = list->value; |
2015 | |
2016 | if (!strncmp(chr_info->label, str, len)) { |
2017 | Chardev *chr = qemu_chr_find(chr_info->label); |
2018 | if (chr && CHARDEV_IS_RINGBUF(chr)) { |
2019 | readline_add_completion(rs, chr_info->label); |
2020 | } |
2021 | } |
2022 | list = list->next; |
2023 | } |
2024 | qapi_free_ChardevInfoList(start); |
2025 | } |
2026 | |
2027 | void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str) |
2028 | { |
2029 | if (nb_args != 2) { |
2030 | return; |
2031 | } |
2032 | ringbuf_completion(rs, str); |
2033 | } |
2034 | |
2035 | void device_del_completion(ReadLineState *rs, int nb_args, const char *str) |
2036 | { |
2037 | size_t len; |
2038 | |
2039 | if (nb_args != 2) { |
2040 | return; |
2041 | } |
2042 | |
2043 | len = strlen(str); |
2044 | readline_set_completion_index(rs, len); |
2045 | peripheral_device_del_completion(rs, str, len); |
2046 | } |
2047 | |
2048 | void object_del_completion(ReadLineState *rs, int nb_args, const char *str) |
2049 | { |
2050 | ObjectPropertyInfoList *list, *start; |
2051 | size_t len; |
2052 | |
2053 | if (nb_args != 2) { |
2054 | return; |
2055 | } |
2056 | len = strlen(str); |
2057 | readline_set_completion_index(rs, len); |
2058 | |
2059 | start = list = qmp_qom_list("/objects" , NULL); |
2060 | while (list) { |
2061 | ObjectPropertyInfo *info = list->value; |
2062 | |
2063 | if (!strncmp(info->type, "child<" , 5) |
2064 | && !strncmp(info->name, str, len)) { |
2065 | readline_add_completion(rs, info->name); |
2066 | } |
2067 | list = list->next; |
2068 | } |
2069 | qapi_free_ObjectPropertyInfoList(start); |
2070 | } |
2071 | |
2072 | void sendkey_completion(ReadLineState *rs, int nb_args, const char *str) |
2073 | { |
2074 | int i; |
2075 | char *sep; |
2076 | size_t len; |
2077 | |
2078 | if (nb_args != 2) { |
2079 | return; |
2080 | } |
2081 | sep = strrchr(str, '-'); |
2082 | if (sep) { |
2083 | str = sep + 1; |
2084 | } |
2085 | len = strlen(str); |
2086 | readline_set_completion_index(rs, len); |
2087 | for (i = 0; i < Q_KEY_CODE__MAX; i++) { |
2088 | if (!strncmp(str, QKeyCode_str(i), len)) { |
2089 | readline_add_completion(rs, QKeyCode_str(i)); |
2090 | } |
2091 | } |
2092 | } |
2093 | |
2094 | void set_link_completion(ReadLineState *rs, int nb_args, const char *str) |
2095 | { |
2096 | size_t len; |
2097 | |
2098 | len = strlen(str); |
2099 | readline_set_completion_index(rs, len); |
2100 | if (nb_args == 2) { |
2101 | NetClientState *ncs[MAX_QUEUE_NUM]; |
2102 | int count, i; |
2103 | count = qemu_find_net_clients_except(NULL, ncs, |
2104 | NET_CLIENT_DRIVER_NONE, |
2105 | MAX_QUEUE_NUM); |
2106 | for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { |
2107 | const char *name = ncs[i]->name; |
2108 | if (!strncmp(str, name, len)) { |
2109 | readline_add_completion(rs, name); |
2110 | } |
2111 | } |
2112 | } else if (nb_args == 3) { |
2113 | add_completion_option(rs, str, "on" ); |
2114 | add_completion_option(rs, str, "off" ); |
2115 | } |
2116 | } |
2117 | |
2118 | void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) |
2119 | { |
2120 | int len, count, i; |
2121 | NetClientState *ncs[MAX_QUEUE_NUM]; |
2122 | |
2123 | if (nb_args != 2) { |
2124 | return; |
2125 | } |
2126 | |
2127 | len = strlen(str); |
2128 | readline_set_completion_index(rs, len); |
2129 | count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC, |
2130 | MAX_QUEUE_NUM); |
2131 | for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { |
2132 | QemuOpts *opts; |
2133 | const char *name = ncs[i]->name; |
2134 | if (strncmp(str, name, len)) { |
2135 | continue; |
2136 | } |
2137 | opts = qemu_opts_find(qemu_find_opts_err("netdev" , NULL), name); |
2138 | if (opts) { |
2139 | readline_add_completion(rs, name); |
2140 | } |
2141 | } |
2142 | } |
2143 | |
2144 | void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str) |
2145 | { |
2146 | size_t len; |
2147 | |
2148 | len = strlen(str); |
2149 | readline_set_completion_index(rs, len); |
2150 | if (nb_args == 2) { |
2151 | TraceEventIter iter; |
2152 | TraceEvent *ev; |
2153 | char *pattern = g_strdup_printf("%s*" , str); |
2154 | trace_event_iter_init(&iter, pattern); |
2155 | while ((ev = trace_event_iter_next(&iter)) != NULL) { |
2156 | readline_add_completion(rs, trace_event_get_name(ev)); |
2157 | } |
2158 | g_free(pattern); |
2159 | } |
2160 | } |
2161 | |
2162 | void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) |
2163 | { |
2164 | size_t len; |
2165 | |
2166 | len = strlen(str); |
2167 | readline_set_completion_index(rs, len); |
2168 | if (nb_args == 2) { |
2169 | TraceEventIter iter; |
2170 | TraceEvent *ev; |
2171 | char *pattern = g_strdup_printf("%s*" , str); |
2172 | trace_event_iter_init(&iter, pattern); |
2173 | while ((ev = trace_event_iter_next(&iter)) != NULL) { |
2174 | readline_add_completion(rs, trace_event_get_name(ev)); |
2175 | } |
2176 | g_free(pattern); |
2177 | } else if (nb_args == 3) { |
2178 | add_completion_option(rs, str, "on" ); |
2179 | add_completion_option(rs, str, "off" ); |
2180 | } |
2181 | } |
2182 | |
2183 | void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) |
2184 | { |
2185 | int i; |
2186 | |
2187 | if (nb_args != 2) { |
2188 | return; |
2189 | } |
2190 | readline_set_completion_index(rs, strlen(str)); |
2191 | for (i = 0; i < WATCHDOG_ACTION__MAX; i++) { |
2192 | add_completion_option(rs, str, WatchdogAction_str(i)); |
2193 | } |
2194 | } |
2195 | |
2196 | void migrate_set_capability_completion(ReadLineState *rs, int nb_args, |
2197 | const char *str) |
2198 | { |
2199 | size_t len; |
2200 | |
2201 | len = strlen(str); |
2202 | readline_set_completion_index(rs, len); |
2203 | if (nb_args == 2) { |
2204 | int i; |
2205 | for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { |
2206 | const char *name = MigrationCapability_str(i); |
2207 | if (!strncmp(str, name, len)) { |
2208 | readline_add_completion(rs, name); |
2209 | } |
2210 | } |
2211 | } else if (nb_args == 3) { |
2212 | add_completion_option(rs, str, "on" ); |
2213 | add_completion_option(rs, str, "off" ); |
2214 | } |
2215 | } |
2216 | |
2217 | void migrate_set_parameter_completion(ReadLineState *rs, int nb_args, |
2218 | const char *str) |
2219 | { |
2220 | size_t len; |
2221 | |
2222 | len = strlen(str); |
2223 | readline_set_completion_index(rs, len); |
2224 | if (nb_args == 2) { |
2225 | int i; |
2226 | for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { |
2227 | const char *name = MigrationParameter_str(i); |
2228 | if (!strncmp(str, name, len)) { |
2229 | readline_add_completion(rs, name); |
2230 | } |
2231 | } |
2232 | } |
2233 | } |
2234 | |
2235 | static void vm_completion(ReadLineState *rs, const char *str) |
2236 | { |
2237 | size_t len; |
2238 | BlockDriverState *bs; |
2239 | BdrvNextIterator it; |
2240 | |
2241 | len = strlen(str); |
2242 | readline_set_completion_index(rs, len); |
2243 | |
2244 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { |
2245 | SnapshotInfoList *snapshots, *snapshot; |
2246 | AioContext *ctx = bdrv_get_aio_context(bs); |
2247 | bool ok = false; |
2248 | |
2249 | aio_context_acquire(ctx); |
2250 | if (bdrv_can_snapshot(bs)) { |
2251 | ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0; |
2252 | } |
2253 | aio_context_release(ctx); |
2254 | if (!ok) { |
2255 | continue; |
2256 | } |
2257 | |
2258 | snapshot = snapshots; |
2259 | while (snapshot) { |
2260 | char *completion = snapshot->value->name; |
2261 | if (!strncmp(str, completion, len)) { |
2262 | readline_add_completion(rs, completion); |
2263 | } |
2264 | completion = snapshot->value->id; |
2265 | if (!strncmp(str, completion, len)) { |
2266 | readline_add_completion(rs, completion); |
2267 | } |
2268 | snapshot = snapshot->next; |
2269 | } |
2270 | qapi_free_SnapshotInfoList(snapshots); |
2271 | } |
2272 | |
2273 | } |
2274 | |
2275 | void delvm_completion(ReadLineState *rs, int nb_args, const char *str) |
2276 | { |
2277 | if (nb_args == 2) { |
2278 | vm_completion(rs, str); |
2279 | } |
2280 | } |
2281 | |
2282 | void loadvm_completion(ReadLineState *rs, int nb_args, const char *str) |
2283 | { |
2284 | if (nb_args == 2) { |
2285 | vm_completion(rs, str); |
2286 | } |
2287 | } |
2288 | |
2289 | static int |
2290 | compare_mon_cmd(const void *a, const void *b) |
2291 | { |
2292 | return strcmp(((const HMPCommand *)a)->name, |
2293 | ((const HMPCommand *)b)->name); |
2294 | } |
2295 | |
2296 | static void sortcmdlist(void) |
2297 | { |
2298 | qsort(hmp_cmds, ARRAY_SIZE(hmp_cmds) - 1, |
2299 | sizeof(*hmp_cmds), |
2300 | compare_mon_cmd); |
2301 | qsort(hmp_info_cmds, ARRAY_SIZE(hmp_info_cmds) - 1, |
2302 | sizeof(*hmp_info_cmds), |
2303 | compare_mon_cmd); |
2304 | } |
2305 | |
2306 | void monitor_init_globals(void) |
2307 | { |
2308 | monitor_init_globals_core(); |
2309 | monitor_init_qmp_commands(); |
2310 | sortcmdlist(); |
2311 | qemu_mutex_init(&mon_fdsets_lock); |
2312 | } |
2313 | |