| /* Regression test for state explosion seen whilst implementing |
| PR analyzer/110426, involving an explosion in the number of |
| conjured_svalues whilst handling a long chain of external |
| function calls. */ |
| |
| /* { dg-additional-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ |
| |
| #define NULL ((void *)0) |
| typedef unsigned char uint8_t; |
| typedef unsigned short int uint16_t; |
| typedef unsigned int uint32_t; |
| typedef struct Error Error; |
| typedef struct QEMUTimer QEMUTimer; |
| enum libusb_class_code { |
| LIBUSB_CLASS_PER_INTERFACE = 0x00, |
| }; |
| struct libusb_device_descriptor {}; |
| struct libusb_endpoint_descriptor { |
| uint8_t bEndpointAddress; |
| uint8_t bmAttributes; |
| }; |
| struct libusb_interface_descriptor { |
| uint8_t bNumEndpoints; |
| const struct libusb_endpoint_descriptor *endpoint; |
| }; |
| struct libusb_interface { |
| const struct libusb_interface_descriptor *altsetting; |
| }; |
| struct libusb_config_descriptor { |
| uint8_t bNumInterfaces; |
| const struct libusb_interface *interface; |
| }; |
| typedef struct libusb_context libusb_context; |
| typedef struct libusb_device libusb_device; |
| typedef struct libusb_device_handle libusb_device_handle; |
| enum libusb_speed { |
| LIBUSB_SUCCESS = 0, |
| LIBUSB_TRANSFER_TYPE_BULK = 2U, |
| }; |
| typedef struct USBDevice USBDevice; |
| typedef struct USBHostDevice USBHostDevice; |
| struct USBAutoFilter { |
| uint32_t bus_num; |
| }; |
| struct USBHostDevice { |
| struct USBAutoFilter match; |
| struct USBHostDevice *tqe_next; |
| int bus_num; |
| int addr; |
| char port[16]; |
| libusb_device *dev; |
| libusb_device_handle *dh; |
| struct libusb_device_descriptor ddesc; |
| }; |
| static union { struct USBHostDevice *tqh_first; } hostdevs = {}; |
| static libusb_context *ctx; |
| static void usb_host_ep_update(USBHostDevice *s) { |
| static const char *tname[] = {}; |
| USBDevice *udev = USB_DEVICE(s); |
| struct libusb_config_descriptor *conf; |
| const struct libusb_interface_descriptor *intf; |
| const struct libusb_endpoint_descriptor *endp; |
| struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp; |
| uint8_t devep, type; |
| int ep; |
| int rc, i, e; |
| usb_ep_reset(udev); |
| rc = libusb_get_active_config_descriptor(s->dev, &conf); |
| for (i = 0; i < conf->bNumInterfaces; i++) { |
| intf = &conf->interface[i].altsetting[0]; |
| trace_usb_host_parse_interface(); |
| for (e = 0; e < intf->bNumEndpoints; e++) { |
| endp = &intf->endpoint[e]; |
| devep = endp->bEndpointAddress; |
| ep = devep & 0xf; |
| type = endp->bmAttributes & 0x3; |
| if (usb_ep_get_type(udev) != 255) { |
| trace_usb_host_parse_error(); |
| } |
| trace_usb_host_parse_endpoint(s->bus_num, s->addr); |
| usb_ep_set_max_packet_size(udev); |
| usb_ep_set_type(udev); |
| usb_ep_set_ifnum(udev); |
| usb_ep_set_halted(udev); |
| if (type == LIBUSB_TRANSFER_TYPE_BULK && |
| libusb_get_ss_endpoint_companion_descriptor( |
| ctx, endp, &endp_ss_comp) == LIBUSB_SUCCESS) { |
| usb_ep_set_max_streams(udev); |
| libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp); |
| } |
| } |
| } |
| } |
| static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd) { |
| USBDevice *udev = USB_DEVICE(s); |
| int bus_num = 0; |
| int addr = 0; |
| Error *local_err = NULL; |
| if (dev) { |
| bus_num = libusb_get_bus_number(dev); |
| addr = libusb_get_device_address(dev); |
| trace_usb_host_open_started(bus_num, addr); |
| libusb_open(dev, &s->dh); |
| trace_usb_host_open_hostfd(hostfd); |
| libusb_wrap_sys_device(ctx, &s->dh); |
| dev = libusb_get_device(s->dh); |
| bus_num = libusb_get_bus_number(dev); |
| addr = libusb_get_device_address(dev); |
| } |
| usb_host_detach_kernel(s); |
| libusb_get_device_descriptor(dev, &s->ddesc); |
| usb_host_get_port(s->dev, s->port, sizeof(s->port)); |
| usb_ep_init(udev); |
| usb_host_ep_update(s); |
| libusb_get_device_speed(dev); |
| usb_device_attach(udev, &local_err); |
| if (local_err) { |
| error_report_err(local_err); |
| goto fail; |
| } |
| return 0; |
| fail: |
| trace_usb_host_open_failure(); |
| if (s->dh != NULL) { |
| usb_host_release_interfaces(s); |
| libusb_reset_device(s->dh); |
| usb_host_attach_kernel(s); |
| } |
| } |
| static QEMUTimer *usb_auto_timer; |
| static void usb_host_vm_state(void *unused, _Bool running) {} |
| static void usb_host_auto_check(void *unused) { |
| struct USBHostDevice *s; |
| struct USBAutoFilter *f; |
| libusb_device **devs = NULL; |
| struct libusb_device_descriptor ddesc; |
| int i, n; |
| if (usb_host_init() != 0) { |
| n = libusb_get_device_list(ctx, &devs); |
| for (i = 0; i < n; i++) { |
| if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) { |
| } |
| for ((s) = ((&hostdevs)->tqh_first); (s); (s) = ((s)->tqe_next)) { |
| f = &s->match; |
| if (f->bus_num > 0 && f->bus_num != libusb_get_bus_number(devs[i])) { |
| } |
| if (usb_host_open(s, devs[i], 0) < 0) { |
| } |
| } |
| } |
| libusb_free_device_list(devs, 1); |
| qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); |
| timer_new_ms(usb_host_auto_check, NULL); |
| trace_usb_host_auto_scan_enabled(); |
| } |
| timer_mod(usb_auto_timer, qemu_clock_get_ms() + 2000); |
| } |