diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..b25c15b81fa --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/adb/MODULE_LICENSE_APACHE2 b/adb/MODULE_LICENSE_APACHE2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/adb/NOTICE b/adb/NOTICE new file mode 100644 index 00000000000..9ffcc081334 --- /dev/null +++ b/adb/NOTICE @@ -0,0 +1,191 @@ + + Copyright (c) 2006-2009, The Android Open Source Project + Copyright 2006, Brian Swetland + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/adb/adb.c b/adb/adb.c index e8d2c8fa8bc..c1646b807b5 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -832,6 +832,7 @@ int adb_main(int is_daemon) { #if !ADB_HOST int secure = 0; + int port; char value[PROPERTY_VALUE_MAX]; #endif @@ -850,7 +851,7 @@ int adb_main(int is_daemon) HOST = 1; usb_vendors_init(); usb_init(); - local_init(); + local_init(ADB_LOCAL_TRANSPORT_PORT); if(install_listener("tcp:5037", "*smartsocket*", NULL)) { exit(1); @@ -918,14 +919,19 @@ int adb_main(int is_daemon) } /* for the device, start the usb transport if the - ** android usb device exists, otherwise start the - ** network transport. + ** android usb device exists and "service.adb.tcp" + ** is not set, otherwise start the network transport. */ - if(access("/dev/android_adb", F_OK) == 0 || - access("/dev/android", F_OK) == 0) { + property_get("service.adb.tcp.port", value, "0"); + if (sscanf(value, "%d", &port) == 1 && port > 0) { + // listen on TCP port specified by service.adb.tcp.port property + local_init(port); + } else if (access("/dev/android_adb", F_OK) == 0) { + // listen on USB usb_init(); } else { - local_init(); + // listen on default port + local_init(ADB_LOCAL_TRANSPORT_PORT); } init_jdwp(); #endif @@ -1006,6 +1012,66 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r return 0; } + // add a new TCP transport + if (!strncmp(service, "connect:", 8)) { + char buffer[4096]; + int port, fd; + char* host = service + 8; + char* portstr = strchr(host, ':'); + + if (!portstr) { + snprintf(buffer, sizeof(buffer), "unable to parse %s as :", host); + goto done; + } + if (find_transport(host)) { + snprintf(buffer, sizeof(buffer), "Already connected to %s", host); + goto done; + } + + // zero terminate host by overwriting the ':' + *portstr++ = 0; + if (sscanf(portstr, "%d", &port) == 0) { + snprintf(buffer, sizeof(buffer), "bad port number %s", portstr); + goto done; + } + + fd = socket_network_client(host, port, SOCK_STREAM); + if (fd < 0) { + snprintf(buffer, sizeof(buffer), "unable to connect to %s:%d", host, port); + goto done; + } + + D("client: connected on remote on fd %d\n", fd); + close_on_exec(fd); + disable_tcp_nagle(fd); + snprintf(buf, sizeof buf, "%s:%d", host, port); + register_socket_transport(fd, buf, port, 0); + snprintf(buffer, sizeof(buffer), "connected to %s:%d", host, port); + +done: + snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); + writex(reply_fd, buf, strlen(buf)); + return 0; + } + + // remove TCP transport + if (!strncmp(service, "disconnect:", 11)) { + char buffer[4096]; + memset(buffer, 0, sizeof(buffer)); + char* serial = service + 11; + atransport *t = find_transport(serial); + + if (t) { + unregister_transport(t); + } else { + snprintf(buffer, sizeof(buffer), "No such device %s", serial); + } + + snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); + writex(reply_fd, buf, strlen(buf)); + return 0; + } + // returns our value for ADB_SERVER_VERSION if (!strcmp(service, "version")) { char version[12]; diff --git a/adb/adb.h b/adb/adb.h index 8d57bf26c5b..b95868262e7 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -33,7 +33,7 @@ #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information -#define ADB_SERVER_VERSION 22 // Increment this when we want to force users to start a new adb server +#define ADB_SERVER_VERSION 25 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; @@ -262,15 +262,24 @@ void run_transport_disconnects( atransport* t ); void kick_transport( atransport* t ); /* initialize a transport object's func pointers and state */ -int init_socket_transport(atransport *t, int s, int port); -void init_usb_transport(atransport *t, usb_handle *usb); +int init_socket_transport(atransport *t, int s, int port, int local); +void init_usb_transport(atransport *t, usb_handle *usb, int state); /* for MacOS X cleanup */ void close_usb_devices(); /* cause new transports to be init'd and added to the list */ -void register_socket_transport(int s, const char *serial, int port); -void register_usb_transport(usb_handle *h, const char *serial); +void register_socket_transport(int s, const char *serial, int port, int local); + +/* this should only be used for the "adb disconnect" command */ +void unregister_transport(atransport *t); + +void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable); + +/* this should only be used for transports with connection_state == CS_NOPERM */ +void unregister_usb_transport(usb_handle *usb); + +atransport *find_transport(const char *serial); int service_to_fd(const char *name); #if ADB_HOST @@ -357,7 +366,7 @@ typedef enum { #define ADB_PROTOCOL 0x1 -void local_init(); +void local_init(int port); int local_connect(int port); /* usb host/client interface */ @@ -384,7 +393,7 @@ int connection_state(atransport *t); #define CS_DEVICE 2 #define CS_HOST 3 #define CS_RECOVERY 4 -#define CS_ERROR 5 +#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ extern int HOST; diff --git a/adb/commandline.c b/adb/commandline.c index 5414e5eb53f..055aa104e73 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -96,7 +96,8 @@ void help() " -e - directs command to the only running emulator.\n" " returns an error if more than one emulator is running.\n" " -s - directs command to the USB device or emulator with\n" - " the given serial number\n" + " the given serial number. Overrides ANDROID_SERIAL\n" + " envivornment variable.\n" " -p - simple product name like 'sooner', or\n" " a relative/absolute path to a product\n" " out directory like 'out/target/product/sooner'.\n" @@ -104,6 +105,8 @@ void help() " environment variable is used, which must\n" " be an absolute path.\n" " devices - list all connected devices\n" + " connect : - connect to a device via TCP/IP" + " disconnect : - disconnect from a TCP/IP device" "\n" "device commands:\n" " adb push - copy file/dir to device\n" @@ -148,7 +151,9 @@ void help() " adb status-window - continuously print device status for a specified device\n" " adb remount - remounts the /system partition on the device read-write\n" " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" - " adb root - restarts adb with root permissions\n" + " adb root - restarts the adbd daemon with root permissions\n" + " adb usb - restarts the adbd daemon listening on USB" + " adb tcpip - restarts the adbd daemon listening on TCP on the specified port" "\n" "networking:\n" " adb ppp [parameters] - Run PPP over USB.\n" @@ -767,6 +772,8 @@ int adb_commandline(int argc, char **argv) } // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint + serial = getenv("ANDROID_SERIAL"); + /* modifiers and flags */ while(argc > 0) { if(!strcmp(argv[0],"nodaemon")) { @@ -847,6 +854,22 @@ int adb_commandline(int argc, char **argv) } } + if(!strcmp(argv[0], "connect") || !strcmp(argv[0], "disconnect")) { + char *tmp; + if (argc != 2) { + fprintf(stderr, "Usage: adb %s :\n", argv[0]); + return 1; + } + snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]); + tmp = adb_query(buf); + if(tmp) { + printf("%s\n", tmp); + return 0; + } else { + return 1; + } + } + if (!strcmp(argv[0], "emu")) { return adb_send_emulator_command(argc, argv); } @@ -905,35 +928,15 @@ int adb_commandline(int argc, char **argv) return 0; } - if(!strcmp(argv[0], "remount")) { - int fd = adb_connect("remount:"); - if(fd >= 0) { - read_and_dump(fd); - adb_close(fd); - return 0; - } - fprintf(stderr,"error: %s\n", adb_error()); - return 1; - } - - if(!strcmp(argv[0], "reboot")) { - int fd; + if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") + || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") + || !strcmp(argv[0], "root")) { + char command[100]; if (argc > 1) - snprintf(buf, sizeof(buf), "reboot:%s", argv[1]); + snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]); else - snprintf(buf, sizeof(buf), "reboot:"); - fd = adb_connect(buf); - if(fd >= 0) { - read_and_dump(fd); - adb_close(fd); - return 0; - } - fprintf(stderr,"error: %s\n", adb_error()); - return 1; - } - - if(!strcmp(argv[0], "root")) { - int fd = adb_connect("root:"); + snprintf(command, sizeof(command), "%s:", argv[0]); + int fd = adb_connect(command); if(fd >= 0) { read_and_dump(fd); adb_close(fd); diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c index 65cb20a106c..2f456947082 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.c @@ -28,18 +28,35 @@ #include /* TODO: -** - grab the current buffer, not the first buffer ** - sync with vsync to avoid tearing */ +/* This version number defines the format of the fbinfo struct. + It must match versioning in ddms where this data is consumed. */ +#define DDMS_RAWIMAGE_VERSION 1 +struct fbinfo { + unsigned int version; + unsigned int bpp; + unsigned int size; + unsigned int width; + unsigned int height; + unsigned int red_offset; + unsigned int red_length; + unsigned int blue_offset; + unsigned int blue_length; + unsigned int green_offset; + unsigned int green_length; + unsigned int alpha_offset; + unsigned int alpha_length; +} __attribute__((packed)); void framebuffer_service(int fd, void *cookie) { struct fb_var_screeninfo vinfo; - int fb; - void *ptr = MAP_FAILED; - char x; + int fb, offset; + char x[256]; - unsigned fbinfo[4]; + struct fbinfo fbinfo; + unsigned i, bytespp; fb = open("/dev/graphics/fb0", O_RDONLY); if(fb < 0) goto done; @@ -47,24 +64,43 @@ void framebuffer_service(int fd, void *cookie) if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) goto done; fcntl(fb, F_SETFD, FD_CLOEXEC); - fbinfo[0] = 16; - fbinfo[1] = vinfo.xres * vinfo.yres * 2; - fbinfo[2] = vinfo.xres; - fbinfo[3] = vinfo.yres; + bytespp = vinfo.bits_per_pixel / 8; - ptr = mmap(0, fbinfo[1], PROT_READ, MAP_SHARED, fb, 0); - if(ptr == MAP_FAILED) goto done; + fbinfo.version = DDMS_RAWIMAGE_VERSION; + fbinfo.bpp = vinfo.bits_per_pixel; + fbinfo.size = vinfo.xres * vinfo.yres * bytespp; + fbinfo.width = vinfo.xres; + fbinfo.height = vinfo.yres; + fbinfo.red_offset = vinfo.red.offset; + fbinfo.red_length = vinfo.red.length; + fbinfo.green_offset = vinfo.green.offset; + fbinfo.green_length = vinfo.green.length; + fbinfo.blue_offset = vinfo.blue.offset; + fbinfo.blue_length = vinfo.blue.length; + fbinfo.alpha_offset = vinfo.transp.offset; + fbinfo.alpha_length = vinfo.transp.length; - if(writex(fd, fbinfo, sizeof(unsigned) * 4)) goto done; + /* HACK: for several of our 3d cores a specific alignment + * is required so the start of the fb may not be an integer number of lines + * from the base. As a result we are storing the additional offset in + * xoffset. This is not the correct usage for xoffset, it should be added + * to each line, not just once at the beginning */ + offset = vinfo.xoffset * bytespp; - for(;;) { - if(readx(fd, &x, 1)) goto done; - if(writex(fd, ptr, fbinfo[1])) goto done; + offset += vinfo.xres * vinfo.yoffset * bytespp; + + if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; + + lseek(fb, offset, SEEK_SET); + for(i = 0; i < fbinfo.size; i += 256) { + if(readx(fb, &x, 256)) goto done; + if(writex(fd, &x, 256)) goto done; } + if(readx(fb, &x, fbinfo.size % 256)) goto done; + if(writex(fd, &x, fbinfo.size % 256)) goto done; + done: - if(ptr != MAP_FAILED) munmap(ptr, fbinfo[1]); if(fb >= 0) close(fb); close(fd); } - diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c index 00dfee433e1..6125cb427ab 100644 --- a/adb/get_my_path_darwin.c +++ b/adb/get_my_path_darwin.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #import #include diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c index ae7f12dfd14..0c26f7b66b1 100644 --- a/adb/jdwp_service.c +++ b/adb/jdwp_service.c @@ -164,7 +164,7 @@ jdwp_process_free( JdwpProcess* proc ) proc->next->prev = proc->prev; if (proc->socket >= 0) { - shutdown(proc->socket, SHUT_RDWR); + adb_shutdown(proc->socket); adb_close(proc->socket); proc->socket = -1; } diff --git a/adb/services.c b/adb/services.c index 517da55f586..b5df5542b93 100644 --- a/adb/services.c +++ b/adb/services.c @@ -32,8 +32,7 @@ # include # endif #else -#include -#include +# include #endif typedef struct stinfo stinfo; @@ -64,6 +63,7 @@ static void dns_service(int fd, void *cookie) adb_mutex_lock(&dns_lock); hp = gethostbyname(hostname); + free(cookie); if(hp == 0) { writex(fd, &zero, 4); } else { @@ -120,6 +120,7 @@ void restart_root_service(int fd, void *cookie) if (strcmp(value, "1") != 0) { snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n"); writex(fd, buf, strlen(buf)); + adb_close(fd); return; } @@ -134,17 +135,57 @@ void restart_root_service(int fd, void *cookie) } } -void reboot_service(int fd, char *arg) +void restart_tcp_service(int fd, void *cookie) +{ + char buf[100]; + char value[PROPERTY_VALUE_MAX]; + int port = (int)cookie; + + if (port <= 0) { + snprintf(buf, sizeof(buf), "invalid port\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + return; + } + + snprintf(value, sizeof(value), "%d", port); + property_set("service.adb.tcp.port", value); + snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port); + writex(fd, buf, strlen(buf)); + adb_close(fd); + + // quit, and init will restart us in TCP mode + sleep(1); + exit(1); +} + +void restart_usb_service(int fd, void *cookie) +{ + char buf[100]; + + property_set("service.adb.tcp.port", "0"); + snprintf(buf, sizeof(buf), "restarting in USB mode\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + + // quit, and init will restart us in USB mode + sleep(1); + exit(1); +} + +void reboot_service(int fd, void *arg) { char buf[100]; int ret; sync(); - ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg); + ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, (char *)arg); if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno)); writex(fd, buf, strlen(buf)); } + free(arg); adb_close(fd); } @@ -213,9 +254,12 @@ static int create_service_thread(void (*func)(int, void *), void *cookie) return s[0]; } -#if !ADB_HOST static int create_subprocess(const char *cmd, const char *arg0, const char *arg1) { +#ifdef HAVE_WIN32_PROC + fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); + return -1; +#else /* !HAVE_WIN32_PROC */ char *devname; int ptm; pid_t pid; @@ -258,6 +302,7 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 cmd, strerror(errno), errno); exit(-1); } else { +#if !ADB_HOST // set child's OOM adjustment to zero char text[64]; snprintf(text, sizeof text, "/proc/%d/oom_adj", pid); @@ -268,11 +313,11 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 } else { D("adb: unable to open %s\n", text); } - +#endif return ptm; } +#endif /* !HAVE_WIN32_PROC */ } -#endif /* !ADB_HOST */ #if ADB_HOST #define SHELL_COMMAND "/bin/sh" @@ -280,76 +325,6 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 #define SHELL_COMMAND "/system/bin/sh" #endif -#if !ADB_HOST -static void shell_service(int s, void *command) -{ - char buffer[MAX_PAYLOAD]; - char buffer2[MAX_PAYLOAD]; - struct pollfd ufds[2]; - int fd, ret = 0; - unsigned count = 0; - char** args = (char **)command; - fd = create_subprocess(SHELL_COMMAND, args[0], args[1]); - - while (1) { - while (count < sizeof(buffer)) { - ufds[0].fd = fd; - ufds[0].events = POLLIN | POLLHUP; - ufds[0].revents = 0; - ufds[1].fd = s; - ufds[1].events = POLLIN | POLLHUP; - ufds[1].revents = 0; - // use a 100ms timeout so we don't block indefinitely with our - // buffer partially filled. - ret = poll(ufds, 2, 100); - if (ret <= 0) { - D("poll returned %d\n", ret); - // file has closed or we timed out - // set ret to 1 so we don't exit the outer loop - ret = 1; - break; - } - - if (ufds[0].revents & POLLIN) { - ret = adb_read(fd, buffer + count, sizeof(buffer) - count); - D("read fd ret: %d, count: %d\n", ret, count); - if (ret > 0) - count += ret; - else - break; - } - if (ufds[1].revents & POLLIN) { - ret = adb_read(s, buffer2, sizeof(buffer2)); - D("read s ret: %d\n", ret); - if (ret > 0) - adb_write(fd, buffer2, ret); - else - break; - } - - if ((ufds[0].revents & POLLHUP) || (ufds[1].revents & POLLHUP)) { - // set flag to exit after flushing the buffer - ret = -1; - break; - } - } - - D("writing: %d\n", count); - if (count > 0) { - adb_write(s, buffer, count); - count = 0; - } - if (ret <= 0) - break; - } - - D("shell_service done\n"); - - adb_close(fd); - adb_close(s); -} -#endif // !ADB_HOST - int service_to_fd(const char *name) { int ret = -1; @@ -400,27 +375,32 @@ int service_to_fd(const char *name) ret = create_jdwp_connection_fd(atoi(name+5)); } else if (!strncmp(name, "log:", 4)) { ret = create_service_thread(log_service, get_log_file_path(name + 4)); +#endif } else if(!HOST && !strncmp(name, "shell:", 6)) { - const char* args[2]; if(name[6]) { - args[0] = "-c"; - args[1] = name + 6; + ret = create_subprocess(SHELL_COMMAND, "-c", name + 6); } else { - args[0] = "-"; - args[1] = 0; + ret = create_subprocess(SHELL_COMMAND, "-", 0); } - ret = create_service_thread(shell_service, (void *)args); +#if !ADB_HOST } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { - char* arg = name + 7; - if (*name == 0) - arg = NULL; + void* arg = strdup(name + 7); + if(arg == 0) return -1; ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); + } else if(!strncmp(name, "tcpip:", 6)) { + int port; + if (sscanf(name + 6, "%d", &port) == 0) { + port = 0; + } + ret = create_service_thread(restart_tcp_service, (void *)port); + } else if(!strncmp(name, "usb:", 4)) { + ret = create_service_thread(restart_usb_service, NULL); #endif #if 0 } else if(!strncmp(name, "echo:", 5)){ diff --git a/adb/sysdeps.h b/adb/sysdeps.h index 389fbd210ba..63726491a76 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -113,6 +113,7 @@ extern int adb_creat(const char* path, int mode); extern int adb_read(int fd, void* buf, int len); extern int adb_write(int fd, const void* buf, int len); extern int adb_lseek(int fd, int pos, int where); +extern int adb_shutdown(int fd); extern int adb_close(int fd); static __inline__ int unix_close(int fd) @@ -327,6 +328,13 @@ static __inline__ int adb_open( const char* pathname, int options ) #undef open #define open ___xxx_open +static __inline__ int adb_shutdown(int fd) +{ + return shutdown(fd, SHUT_RDWR); +} +#undef shutdown +#define shutdown ____xxx_shutdown + static __inline__ int adb_close(int fd) { return close(fd); diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c index a8e3bb98011..ced91e83862 100644 --- a/adb/sysdeps_win32.c +++ b/adb/sysdeps_win32.c @@ -435,6 +435,20 @@ int adb_lseek(int fd, int pos, int where) } +int adb_shutdown(int fd) +{ + FH f = _fh_from_int(fd); + + if (!f) { + return -1; + } + + D( "adb_shutdown: %s\n", f->name); + shutdown( f->fh_socket, SD_BOTH ); + return 0; +} + + int adb_close(int fd) { FH f = _fh_from_int(fd); diff --git a/adb/transport.c b/adb/transport.c index c76f1a5f8f4..c2877d23971 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -584,17 +584,36 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) return; } + /* don't create transport threads for inaccessible devices */ + if (t->connection_state != CS_NOPERM) { /* initial references are the two threads */ - t->ref_count = 2; + t->ref_count = 2; - if(adb_socketpair(s)) { - fatal_errno("cannot open transport socketpair"); - } + if(adb_socketpair(s)) { + fatal_errno("cannot open transport socketpair"); + } + + D("transport: %p (%d,%d) starting\n", t, s[0], s[1]); + + t->transport_socket = s[0]; + t->fd = s[1]; - D("transport: %p (%d,%d) starting\n", t, s[0], s[1]); + D("transport: %p install %d\n", t, t->transport_socket ); + fdevent_install(&(t->transport_fde), + t->transport_socket, + transport_socket_events, + t); - t->transport_socket = s[0]; - t->fd = s[1]; + fdevent_set(&(t->transport_fde), FDE_READ); + + if(adb_thread_create(&input_thread_ptr, input_thread, t)){ + fatal_errno("cannot create input thread"); + } + + if(adb_thread_create(&output_thread_ptr, output_thread, t)){ + fatal_errno("cannot create output thread"); + } + } /* put us on the master device list */ adb_mutex_lock(&transport_lock); @@ -604,22 +623,6 @@ static void transport_registration_func(int _fd, unsigned ev, void *data) t->prev->next = t; adb_mutex_unlock(&transport_lock); - D("transport: %p install %d\n", t, t->transport_socket ); - fdevent_install(&(t->transport_fde), - t->transport_socket, - transport_socket_events, - t); - - fdevent_set(&(t->transport_fde), FDE_READ); - - if(adb_thread_create(&input_thread_ptr, input_thread, t)){ - fatal_errno("cannot create input thread"); - } - - if(adb_thread_create(&output_thread_ptr, output_thread, t)){ - fatal_errno("cannot create output thread"); - } - t->disconnects.next = t->disconnects.prev = &t->disconnects; update_transports(); @@ -717,6 +720,12 @@ atransport *acquire_one_transport(int state, transport_type ttype, const char* s adb_mutex_lock(&transport_lock); for (t = transport_list.next; t != &transport_list; t = t->next) { + if (t->connection_state == CS_NOPERM) { + if (error_out) + *error_out = "insufficient permissions for device"; + continue; + } + /* check for matching serial number */ if (serial) { if (t->serial && !strcmp(serial, t->serial)) { @@ -763,7 +772,6 @@ atransport *acquire_one_transport(int state, transport_type ttype, const char* s *error_out = "device offline"; result = NULL; } - /* check for required connection state */ if (result && state != CS_ANY && result->connection_state != state) { if (error_out) @@ -793,6 +801,7 @@ static const char *statename(atransport *t) case CS_DEVICE: return "device"; case CS_HOST: return "host"; case CS_RECOVERY: return "recovery"; + case CS_NOPERM: return "no permissions"; default: return "unknown"; } } @@ -807,9 +816,10 @@ int list_transports(char *buf, size_t bufsize) /* XXX OVERRUN PROBLEMS XXX */ adb_mutex_lock(&transport_lock); for(t = transport_list.next; t != &transport_list; t = t->next) { - len = snprintf(p, end - p, "%s\t%s\n", - t->serial ? t->serial : "", - statename(t)); + const char* serial = t->serial; + if (!serial || !serial[0]) + serial = "????????????"; + len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t)); if (p + len >= end) { /* discard last line if buffer is too short */ @@ -839,11 +849,11 @@ void close_usb_devices() } #endif // ADB_HOST -void register_socket_transport(int s, const char *serial, int port) +void register_socket_transport(int s, const char *serial, int port, int local) { atransport *t = calloc(1, sizeof(atransport)); D("transport: %p init'ing for socket %d, on port %d\n", t, s, port); - if ( init_socket_transport(t, s, port) < 0 ) { + if ( init_socket_transport(t, s, port, local) < 0 ) { adb_close(s); free(t); return; @@ -854,18 +864,64 @@ void register_socket_transport(int s, const char *serial, int port) register_transport(t); } -void register_usb_transport(usb_handle *usb, const char *serial) +#if ADB_HOST +atransport *find_transport(const char *serial) +{ + atransport *t; + + adb_mutex_lock(&transport_lock); + for(t = transport_list.next; t != &transport_list; t = t->next) { + if (t->serial && !strcmp(serial, t->serial)) { + break; + } + } + adb_mutex_unlock(&transport_lock); + + if (t != &transport_list) + return t; + else + return 0; +} + +void unregister_transport(atransport *t) +{ + adb_mutex_lock(&transport_lock); + t->next->prev = t->prev; + t->prev->next = t->next; + adb_mutex_unlock(&transport_lock); + + kick_transport(t); + transport_unref(t); +} + +#endif + +void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) { atransport *t = calloc(1, sizeof(atransport)); D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, serial ? serial : ""); - init_usb_transport(t, usb); + init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); if(serial) { t->serial = strdup(serial); } register_transport(t); } +/* this should only be used for transports with connection_state == CS_NOPERM */ +void unregister_usb_transport(usb_handle *usb) +{ + atransport *t; + adb_mutex_lock(&transport_lock); + for(t = transport_list.next; t != &transport_list; t = t->next) { + if (t->usb == usb && t->connection_state == CS_NOPERM) { + t->next->prev = t->prev; + t->prev->next = t->next; + break; + } + } + adb_mutex_unlock(&transport_lock); +} #undef TRACE_TAG #define TRACE_TAG TRACE_RWX diff --git a/adb/transport_local.c b/adb/transport_local.c index be01f290cea..81d120ef119 100644 --- a/adb/transport_local.c +++ b/adb/transport_local.c @@ -122,7 +122,7 @@ int local_connect(int port) close_on_exec(fd); disable_tcp_nagle(fd); snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, port - 1); - register_socket_transport(fd, buf, port); + register_socket_transport(fd, buf, port, 1); return 0; } return -1; @@ -147,17 +147,18 @@ static void *client_socket_thread(void *x) return 0; } -static void *server_socket_thread(void *x) +static void *server_socket_thread(void * arg) { int serverfd, fd; struct sockaddr addr; socklen_t alen; + int port = (int)arg; D("transport: server_socket_thread() starting\n"); serverfd = -1; for(;;) { if(serverfd == -1) { - serverfd = socket_inaddr_any_server(ADB_LOCAL_TRANSPORT_PORT, SOCK_STREAM); + serverfd = socket_inaddr_any_server(port, SOCK_STREAM); if(serverfd < 0) { D("server: cannot bind socket yet\n"); adb_sleep_ms(1000); @@ -167,20 +168,20 @@ static void *server_socket_thread(void *x) } alen = sizeof(addr); - D("server: trying to get new connection from %d\n", ADB_LOCAL_TRANSPORT_PORT); + D("server: trying to get new connection from %d\n", port); fd = adb_socket_accept(serverfd, &addr, &alen); if(fd >= 0) { D("server: new connection on fd %d\n", fd); close_on_exec(fd); disable_tcp_nagle(fd); - register_socket_transport(fd,"host",ADB_LOCAL_TRANSPORT_PORT); + register_socket_transport(fd, "host", port, 1); } } D("transport: server_socket_thread() exiting\n"); return 0; } -void local_init(void) +void local_init(int port) { adb_thread_t thr; void* (*func)(void *); @@ -193,7 +194,7 @@ void local_init(void) D("transport: local %s init\n", HOST ? "client" : "server"); - if(adb_thread_create(&thr, func, 0)) { + if(adb_thread_create(&thr, func, (void *)port)) { fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server"); } @@ -203,6 +204,7 @@ static void remote_kick(atransport *t) { int fd = t->sfd; t->sfd = -1; + adb_shutdown(fd); adb_close(fd); #if ADB_HOST @@ -225,7 +227,7 @@ static void remote_close(atransport *t) adb_close(t->fd); } -int init_socket_transport(atransport *t, int s, int port) +int init_socket_transport(atransport *t, int s, int port, int local) { int fail = 0; @@ -239,7 +241,7 @@ int init_socket_transport(atransport *t, int s, int port) t->type = kTransportLocal; #if ADB_HOST - if (HOST) { + if (HOST && local) { adb_mutex_lock( &local_transports_lock ); { int index = (port - ADB_LOCAL_TRANSPORT_PORT)/2; diff --git a/adb/transport_usb.c b/adb/transport_usb.c index 3737c5c1e63..258416353b5 100644 --- a/adb/transport_usb.c +++ b/adb/transport_usb.c @@ -110,7 +110,7 @@ static void remote_kick(atransport *t) usb_kick(t->usb); } -void init_usb_transport(atransport *t, usb_handle *h) +void init_usb_transport(atransport *t, usb_handle *h, int state) { D("transport: usb\n"); t->close = remote_close; @@ -118,7 +118,7 @@ void init_usb_transport(atransport *t, usb_handle *h) t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sync_token = 1; - t->connection_state = CS_OFFLINE; + t->connection_state = state; t->type = kTransportUsb; t->usb = h; diff --git a/adb/usb_linux.c b/adb/usb_linux.c index 537122d1a6d..863af1dfc48 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -57,6 +57,7 @@ struct usb_handle unsigned char ep_out; unsigned zero_mask; + unsigned writeable; struct usbdevfs_urb urb_in; struct usbdevfs_urb urb_out; @@ -115,7 +116,7 @@ static void kick_disconnected_devices() } static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out, - int ifc, const char *serial, unsigned zero_mask); + int ifc, int serial_index, unsigned zero_mask); static inline int badname(const char *name) { @@ -125,19 +126,18 @@ static inline int badname(const char *name) return 0; } -static int find_usb_device(const char *base, - void (*register_device_callback) (const char *, unsigned char, unsigned char, int, const char *, unsigned)) +static void find_usb_device(const char *base, + void (*register_device_callback) + (const char *, unsigned char, unsigned char, int, int, unsigned)) { char busname[32], devname[32]; unsigned char local_ep_in, local_ep_out; DIR *busdir , *devdir ; struct dirent *de; int fd ; - int found_device = 0; - char serial[256]; busdir = opendir(base); - if(busdir == 0) return 0; + if(busdir == 0) return; while((de = readdir(busdir)) != 0) { if(badname(de->d_name)) continue; @@ -168,7 +168,7 @@ static int find_usb_device(const char *base, } // DBGX("[ scanning %s ]\n", devname); - if((fd = unix_open(devname, O_RDWR)) < 0) { + if((fd = unix_open(devname, O_RDONLY)) < 0) { continue; } @@ -263,67 +263,13 @@ static int find_usb_device(const char *base, local_ep_out = ep1->bEndpointAddress; } - // read the device's serial number - serial[0] = 0; - memset(serial, 0, sizeof(serial)); - if (device->iSerialNumber) { - struct usbdevfs_ctrltransfer ctrl; - __u16 buffer[128]; - __u16 languages[128]; - int i, result; - int languageCount = 0; - - memset(languages, 0, sizeof(languages)); - memset(&ctrl, 0, sizeof(ctrl)); - - // read list of supported languages - ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; - ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; - ctrl.wValue = (USB_DT_STRING << 8) | 0; - ctrl.wIndex = 0; - ctrl.wLength = sizeof(languages); - ctrl.data = languages; - - result = ioctl(fd, USBDEVFS_CONTROL, &ctrl); - if (result > 0) - languageCount = (result - 2) / 2; - - for (i = 1; i <= languageCount; i++) { - memset(buffer, 0, sizeof(buffer)); - memset(&ctrl, 0, sizeof(ctrl)); - - ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; - ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; - ctrl.wValue = (USB_DT_STRING << 8) | device->iSerialNumber; - ctrl.wIndex = languages[i]; - ctrl.wLength = sizeof(buffer); - ctrl.data = buffer; - - result = ioctl(fd, USBDEVFS_CONTROL, &ctrl); - if (result > 0) { - int i; - // skip first word, and copy the rest to the serial string, changing shorts to bytes. - result /= 2; - for (i = 1; i < result; i++) - serial[i - 1] = buffer[i]; - serial[i - 1] = 0; - break; - } - } - } - register_device_callback(devname, local_ep_in, local_ep_out, - interface->bInterfaceNumber, serial, zero_mask); + interface->bInterfaceNumber, device->iSerialNumber, zero_mask); - found_device = 1; break; } else { // seek next interface descriptor - if (i < interfaces - 1) { - while (bufptr[1] != USB_DT_INTERFACE) { - bufptr += bufptr[0]; - } - } + bufptr += (USB_DT_ENDPOINT_SIZE * interface->bNumEndpoints); } } // end of for @@ -332,8 +278,6 @@ static int find_usb_device(const char *base, closedir(devdir); } //end of busdir while closedir(busdir); - - return found_device; } void usb_cleanup() @@ -537,26 +481,30 @@ void usb_kick(usb_handle *h) if(h->dead == 0) { h->dead = 1; - /* HACK ALERT! - ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB). - ** This is a workaround for that problem. - */ - if (h->reaper_thread) { - pthread_kill(h->reaper_thread, SIGALRM); - } + if (h->writeable) { + /* HACK ALERT! + ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB). + ** This is a workaround for that problem. + */ + if (h->reaper_thread) { + pthread_kill(h->reaper_thread, SIGALRM); + } - /* cancel any pending transactions - ** these will quietly fail if the txns are not active, - ** but this ensures that a reader blocked on REAPURB - ** will get unblocked - */ - ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in); - ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out); - h->urb_in.status = -ENODEV; - h->urb_out.status = -ENODEV; - h->urb_in_busy = 0; - h->urb_out_busy = 0; - adb_cond_broadcast(&h->notify); + /* cancel any pending transactions + ** these will quietly fail if the txns are not active, + ** but this ensures that a reader blocked on REAPURB + ** will get unblocked + */ + ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in); + ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out); + h->urb_in.status = -ENODEV; + h->urb_out.status = -ENODEV; + h->urb_in_busy = 0; + h->urb_out_busy = 0; + adb_cond_broadcast(&h->notify); + } else { + unregister_usb_transport(h); + } } adb_mutex_unlock(&h->lock); } @@ -580,11 +528,11 @@ int usb_close(usb_handle *h) static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out, - int interface, - const char *serial, unsigned zero_mask) + int interface, int serial_index, unsigned zero_mask) { usb_handle* usb = 0; int n = 0; + char serial[256]; /* Since Linux will not reassign the device ID (and dev_name) ** as long as the device is open, we can add to the list here @@ -610,6 +558,7 @@ static void register_device(const char *dev_name, usb->ep_in = ep_in; usb->ep_out = ep_out; usb->zero_mask = zero_mask; + usb->writeable = 1; adb_cond_init(&usb->notify, 0); adb_mutex_init(&usb->lock, 0); @@ -618,10 +567,66 @@ static void register_device(const char *dev_name, usb->reaper_thread = 0; usb->desc = unix_open(usb->fname, O_RDWR); - if(usb->desc < 0) goto fail; - D("[ usb open %s fd = %d]\n", usb->fname, usb->desc); - n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); - if(n != 0) goto fail; + if(usb->desc < 0) { + /* if we fail, see if have read-only access */ + usb->desc = unix_open(usb->fname, O_RDONLY); + if(usb->desc < 0) goto fail; + usb->writeable = 0; + D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc); + } else { + D("[ usb open %s fd = %d]\n", usb->fname, usb->desc); + n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); + if(n != 0) goto fail; + } + + /* read the device's serial number */ + serial[0] = 0; + memset(serial, 0, sizeof(serial)); + if (serial_index) { + struct usbdevfs_ctrltransfer ctrl; + __u16 buffer[128]; + __u16 languages[128]; + int i, result; + int languageCount = 0; + + memset(languages, 0, sizeof(languages)); + memset(&ctrl, 0, sizeof(ctrl)); + + // read list of supported languages + ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; + ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; + ctrl.wValue = (USB_DT_STRING << 8) | 0; + ctrl.wIndex = 0; + ctrl.wLength = sizeof(languages); + ctrl.data = languages; + + result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl); + if (result > 0) + languageCount = (result - 2) / 2; + + for (i = 1; i <= languageCount; i++) { + memset(buffer, 0, sizeof(buffer)); + memset(&ctrl, 0, sizeof(ctrl)); + + ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; + ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; + ctrl.wValue = (USB_DT_STRING << 8) | serial_index; + ctrl.wIndex = languages[i]; + ctrl.wLength = sizeof(buffer); + ctrl.data = buffer; + + result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl); + if (result > 0) { + int i; + // skip first word, and copy the rest to the serial string, changing shorts to bytes. + result /= 2; + for (i = 1; i < result; i++) + serial[i - 1] = buffer[i]; + serial[i - 1] = 0; + break; + } + } + } /* add to the end of the active handles */ adb_mutex_lock(&usb_lock); @@ -631,7 +636,7 @@ static void register_device(const char *dev_name, usb->next->prev = usb; adb_mutex_unlock(&usb_lock); - register_usb_transport(usb, serial); + register_usb_transport(usb, serial, usb->writeable); return; fail: diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c index 530bd04db55..0a21c6f2ca3 100644 --- a/adb/usb_linux_client.c +++ b/adb/usb_linux_client.c @@ -72,7 +72,7 @@ static void *usb_open_thread(void *x) usb->fd = fd; D("[ usb_thread - registering device ]\n"); - register_usb_transport(usb, 0); + register_usb_transport(usb, 0, 1); } // never gets here diff --git a/adb/usb_osx.c b/adb/usb_osx.c index 4892c38b3a9..00d02da5bb8 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.c @@ -194,30 +194,54 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); - if (serialIndex > 0) { - IOUSBDevRequest req; - UInt16 buffer[256]; - - req.bmRequestType = - USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); - req.bRequest = kUSBRqGetDescriptor; - req.wValue = (kUSBStringDesc << 8) | serialIndex; - req.wIndex = 0; - req.pData = buffer; - req.wLength = sizeof(buffer); - kr = (*dev)->DeviceRequest(dev, &req); - - if (kr == kIOReturnSuccess && req.wLenDone > 0) { - int i, count; - - // skip first word, and copy the rest to the serial string, - // changing shorts to bytes. - count = (req.wLenDone - 1) / 2; - for (i = 0; i < count; i++) - serial[i] = buffer[i + 1]; - serial[i] = 0; - } - } + if (serialIndex > 0) { + IOUSBDevRequest req; + UInt16 buffer[256]; + UInt16 languages[128]; + + memset(languages, 0, sizeof(languages)); + + req.bmRequestType = + USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); + req.bRequest = kUSBRqGetDescriptor; + req.wValue = (kUSBStringDesc << 8) | 0; + req.wIndex = 0; + req.pData = languages; + req.wLength = sizeof(languages); + kr = (*dev)->DeviceRequest(dev, &req); + + if (kr == kIOReturnSuccess && req.wLenDone > 0) { + + int langCount = (req.wLenDone - 2) / 2, lang; + + for (lang = 1; lang <= langCount; lang++) { + + memset(buffer, 0, sizeof(buffer)); + memset(&req, 0, sizeof(req)); + + req.bmRequestType = + USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); + req.bRequest = kUSBRqGetDescriptor; + req.wValue = (kUSBStringDesc << 8) | serialIndex; + req.wIndex = languages[lang]; + req.pData = buffer; + req.wLength = sizeof(buffer); + kr = (*dev)->DeviceRequest(dev, &req); + + if (kr == kIOReturnSuccess && req.wLenDone > 0) { + int i, count; + + // skip first word, and copy the rest to the serial string, + // changing shorts to bytes. + count = (req.wLenDone - 1) / 2; + for (i = 0; i < count; i++) + serial[i] = buffer[i + 1]; + serial[i] = 0; + break; + } + } + } + } (*dev)->Release(dev); DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product, @@ -232,7 +256,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) } DBG("AndroidDeviceAdded calling register_usb_transport\n"); - register_usb_transport(handle, (serial[0] ? serial : NULL)); + register_usb_transport(handle, (serial[0] ? serial : NULL), 1); // Register for an interest notification of this device being removed. // Pass the reference to our private data as the refCon for the diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index f8c54d7e355..064abc008a7 100644 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -43,6 +43,14 @@ #define VENDOR_ID_SAMSUNG 0x04e8 // Motorola's USB Vendor ID #define VENDOR_ID_MOTOROLA 0x22b8 +// LG's USB Vendor ID +#define VENDOR_ID_LGE 0x1004 +// Huawei's USB Vendor ID +#define VENDOR_ID_HUAWEI 0x12D1 +// Acer's USB Vendor ID +#define VENDOR_ID_ACER 0x0502 +// Sony Ericsson's USB Vendor ID +#define VENDOR_ID_SONY_ERICSSON 0x0FCE /** built-in vendor list */ int builtInVendorIds[] = { @@ -50,6 +58,10 @@ int builtInVendorIds[] = { VENDOR_ID_HTC, VENDOR_ID_SAMSUNG, VENDOR_ID_MOTOROLA, + VENDOR_ID_LGE, + VENDOR_ID_HUAWEI, + VENDOR_ID_ACER, + VENDOR_ID_SONY_ERICSSON, }; #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) diff --git a/adb/usb_windows.c b/adb/usb_windows.c index 0951f670650..38c4cf484f2 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.c @@ -488,7 +488,7 @@ void find_devices() { true)) { // Lets make sure that we don't duplicate this device if (register_new_device(handle)) { - register_usb_transport(handle, serial_number); + register_usb_transport(handle, serial_number, 1); } else { D("register_new_device failed for %s\n", interf_name); usb_cleanup_handle(handle); diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c index 9394e1cacfb..996e6c2044f 100644 --- a/debuggerd/debuggerd.c +++ b/debuggerd/debuggerd.c @@ -2,16 +2,16 @@ ** ** Copyright 2006, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -48,8 +48,6 @@ extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map, int *frame0_pc_sane, bool at_fault); -static char **process_name_ptr; - static int logsocket = -1; #define ANDROID_LOG_INFO 4 @@ -58,7 +56,7 @@ static int logsocket = -1; void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...) { char buf[128]; - + va_list ap; va_start(ap, fmt); @@ -91,16 +89,16 @@ mapinfo *parse_maps_line(char *line) if(len < 1) return 0; line[--len] = 0; - + if(len < 50) return 0; if(line[20] != 'x') return 0; mi = malloc(sizeof(mapinfo) + (len - 47)); if(mi == 0) return 0; - + mi->start = strtoul(line, 0, 16); mi->end = strtoul(line + 9, 0, 16); - /* To be filled in parse_exidx_info if the mapped section starts with + /* To be filled in parse_exidx_info if the mapped section starts with * elf_header */ mi->exidx_start = mi->exidx_end = 0; @@ -120,7 +118,7 @@ void dump_build_info(int tfd) } -void dump_stack_and_code(int tfd, int pid, mapinfo *map, +void dump_stack_and_code(int tfd, int pid, mapinfo *map, int unwind_depth, unsigned int sp_list[], int frame0_pc_sane, bool at_fault) { @@ -128,6 +126,7 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, struct pt_regs r; int sp_depth; bool only_in_tombstone = !at_fault; + char code_buffer[80]; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return; sp = r.ARM_sp; @@ -140,26 +139,53 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, pc = r.ARM_lr; } - _LOG(tfd, true, "code%s:\n", frame0_pc_sane ? "" : " (around frame #01)"); + _LOG(tfd, only_in_tombstone, + "\ncode around %s:\n", frame0_pc_sane ? "pc" : "lr"); end = p = pc & ~3; p -= 16; + end += 16; - /* Dump the code as: - * PC contents + /* Dump the code around PC as: + * addr contents * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 */ while (p <= end) { int i; - _LOG(tfd, true, " %08x ", p); + sprintf(code_buffer, "%08x ", p); for (i = 0; i < 4; i++) { data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - _LOG(tfd, true, " %08x", data); + sprintf(code_buffer + strlen(code_buffer), "%08x ", data); p += 4; } - _LOG(tfd, true, "\n", p); + _LOG(tfd, only_in_tombstone, "%s\n", code_buffer); + } + + if (frame0_pc_sane) { + _LOG(tfd, only_in_tombstone, "\ncode around lr:\n"); + + end = p = r.ARM_lr & ~3; + p -= 16; + end += 16; + + /* Dump the code around LR as: + * addr contents + * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c + * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 + */ + while (p <= end) { + int i; + + sprintf(code_buffer, "%08x ", p); + for (i = 0; i < 4; i++) { + data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); + sprintf(code_buffer + strlen(code_buffer), "%08x ", data); + p += 4; + } + _LOG(tfd, only_in_tombstone, "%s\n", code_buffer); + } } p = sp - 64; @@ -177,7 +203,7 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, end += 0xff; } - _LOG(tfd, only_in_tombstone, "stack:\n"); + _LOG(tfd, only_in_tombstone, "\nstack:\n"); /* If the crash is due to PC == 0, there will be two frames that * have identical SP value. @@ -190,7 +216,7 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, } while (p <= end) { - char *prompt; + char *prompt; char level[16]; data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); if (p == sp_list[sp_depth]) { @@ -200,12 +226,12 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, else { prompt = " "; } - + /* Print the stack content in the log for the first 3 frames. For the * rest only print them in the tombstone file. */ - _LOG(tfd, (sp_depth > 2) || only_in_tombstone, - "%s %08x %08x %s\n", prompt, p, data, + _LOG(tfd, (sp_depth > 2) || only_in_tombstone, + "%s %08x %08x %s\n", prompt, p, data, map_to_name(map, data, "")); p += 4; } @@ -214,14 +240,14 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, end = p+64; while (p <= end) { data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - _LOG(tfd, (sp_depth > 2) || only_in_tombstone, - " %08x %08x %s\n", p, data, + _LOG(tfd, (sp_depth > 2) || only_in_tombstone, + " %08x %08x %s\n", p, data, map_to_name(map, data, "")); p += 4; } } -void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, +void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, bool at_fault) { struct pt_regs r; @@ -239,26 +265,26 @@ void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, map_to_name(map, r.ARM_lr, "")); } -void dump_registers(int tfd, int pid, bool at_fault) +void dump_registers(int tfd, int pid, bool at_fault) { struct pt_regs r; bool only_in_tombstone = !at_fault; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { - _LOG(tfd, only_in_tombstone, + _LOG(tfd, only_in_tombstone, "cannot get registers: %s\n", strerror(errno)); return; } - + _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n", r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3); _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n", r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7); _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n", r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp); - _LOG(tfd, only_in_tombstone, + _LOG(tfd, only_in_tombstone, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr); + r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr); } const char *get_signame(int sig) @@ -277,7 +303,7 @@ const char *get_signame(int sig) void dump_fault_addr(int tfd, int pid, int sig) { siginfo_t si; - + memset(&si, 0, sizeof(si)); if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){ _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno)); @@ -292,20 +318,20 @@ void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig) char data[1024]; char *x = 0; FILE *fp; - + sprintf(data, "/proc/%d/cmdline", pid); fp = fopen(data, "r"); if(fp) { x = fgets(data, 1024, fp); fclose(fp); } - + _LOG(tfd, false, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); dump_build_info(tfd); _LOG(tfd, false, "pid: %d, tid: %d >>> %s <<<\n", pid, tid, x ? x : "UNKNOWN"); - + if(sig) dump_fault_addr(tfd, tid, sig); } @@ -316,10 +342,10 @@ static void parse_exidx_info(mapinfo *milist, pid_t pid) Elf32_Ehdr ehdr; memset(&ehdr, 0, sizeof(Elf32_Ehdr)); - /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of + /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of * mapped section. */ - get_remote_struct(pid, (void *) (mi->start), &ehdr, + get_remote_struct(pid, (void *) (mi->start), &ehdr, sizeof(Elf32_Ehdr)); /* Check if it has the matching magic words */ if (IS_ELF(ehdr)) { @@ -330,7 +356,7 @@ static void parse_exidx_info(mapinfo *milist, pid_t pid) ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff); for (i = 0; i < ehdr.e_phnum; i++) { /* Parse the program header */ - get_remote_struct(pid, (void *) ptr+i, &phdr, + get_remote_struct(pid, (char *) ptr+i, &phdr, sizeof(Elf32_Phdr)); /* Found a EXIDX segment? */ if (phdr.p_type == PT_ARM_EXIDX) { @@ -351,7 +377,7 @@ void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault) unsigned int sp_list[STACK_CONTENT_DEPTH]; int stack_depth; int frame0_pc_sane = 1; - + if (!at_fault) { _LOG(tfd, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); @@ -359,7 +385,7 @@ void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault) } dump_registers(tfd, tid, at_fault); - + /* Clear stack pointer records */ memset(sp_list, 0, sizeof(sp_list)); @@ -401,40 +427,6 @@ void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault) } } -/* FIXME: unused: use it or lose it*/ -#if 0 -static -void start_gdbserver_vs(int pid, int port) -{ - pid_t p; - char *args[5]; - char commspec[16]; - char pidspec[16]; - - p = fork(); - if(p < 0) { - LOG("could not fork()\n"); - return; - } - - if(p == 0) { - sprintf(commspec, ":%d", port); - sprintf(pidspec, "%d", pid); - args[0] = "/system/bin/gdbserver"; - args[1] = commspec; - args[2] = "--attach"; - args[3] = pidspec; - args[4] = 0; - exit(execv(args[0], args)); - } else { - LOG("gdbserver pid=%d port=%d targetpid=%d\n", - p, port, pid); - - sleep(5); - } -} -#endif - #define MAX_TOMBSTONES 10 #define typecheck(x,y) { \ @@ -514,7 +506,7 @@ static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid) while ((de = readdir(d)) != NULL) { unsigned new_tid; /* Ignore "." and ".." */ - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; new_tid = atoi(de->d_name); /* The main thread at fault has been handled individually */ @@ -533,7 +525,7 @@ static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid) } /* Return true if some thread is not detached cleanly */ -static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid, +static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid, int signal) { int fd; @@ -548,7 +540,7 @@ static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid, dump_crash_banner(fd, pid, tid, signal); dump_crash_report(fd, pid, tid, true); - /* + /* * If the user has requested to attach gdb, don't collect the per-thread * information as it increases the chance to lose track of the process. */ @@ -619,7 +611,7 @@ static void wait_for_user_action(unsigned tid, struct ucred* cr) "* adb shell gdbserver :port --attach %d & \n" "* \n" "* and press the HOME key. \n" - "********************************************************\n", + "********************************************************\n", cr->pid, cr->pid); /* wait for HOME key */ @@ -653,13 +645,13 @@ static void wait_for_user_action(unsigned tid, struct ucred* cr) disable_debug_led(); } } - } while (!home); + } while (!home); uninit_getevent(); } /* don't forget to turn debug led off */ disable_debug_led(); - + /* close filedescriptor */ LOG("debuggerd resuming process %d", cr->pid); } @@ -670,7 +662,7 @@ static void handle_crashing_process(int fd) struct stat s; unsigned tid; struct ucred cr; - int n, len, status; + int n, len, status; int tid_attach_status = -1; unsigned retry = 30; bool need_cleanup = false; @@ -678,9 +670,9 @@ static void handle_crashing_process(int fd) char value[PROPERTY_VALUE_MAX]; property_get("debug.db.uid", value, "-1"); int debug_uid = atoi(value); - + XLOG("handle_crashing_process(%d)\n", fd); - + len = sizeof(cr); n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len); if(n != 0) { @@ -688,7 +680,7 @@ static void handle_crashing_process(int fd) goto done; } - XLOG("reading tid\n"); + XLOG("reading tid\n"); fcntl(fd, F_SETFL, O_NONBLOCK); while((n = read(fd, &tid, sizeof(unsigned))) != sizeof(unsigned)) { if(errno == EINTR) continue; @@ -711,7 +703,7 @@ static void handle_crashing_process(int fd) close(fd); return; } - + XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid); tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0); @@ -725,7 +717,7 @@ static void handle_crashing_process(int fd) for(;;) { n = waitpid(tid, &status, __WALL); - + if(n < 0) { if(errno == EAGAIN) continue; LOG("waitpid failed: %s\n", strerror(errno)); @@ -745,7 +737,7 @@ static void handle_crashing_process(int fd) goto done; } continue; - + case SIGILL: case SIGABRT: case SIGBUS: @@ -767,17 +759,17 @@ static void handle_crashing_process(int fd) goto done; } } - + done: XLOG("detaching\n"); - + /* stop the process so we can debug */ kill(cr.pid, SIGSTOP); - /* - * If a thread has been attached by ptrace, make sure it is detached + /* + * If a thread has been attached by ptrace, make sure it is detached * successfully otherwise we will get a zombie. - */ + */ if (tid_attach_status == 0) { int detach_status; /* detach so we can attach gdbserver */ @@ -807,14 +799,12 @@ static void handle_crashing_process(int fd) if(fd != -1) close(fd); } -int main(int argc, char **argv) +int main() { int s; struct sigaction act; - - process_name_ptr = argv; - - logsocket = socket_local_client("logd", + + logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); if(logsocket < 0) { logsocket = -1; @@ -827,23 +817,23 @@ int main(int argc, char **argv) sigaddset(&act.sa_mask,SIGCHLD); act.sa_flags = SA_NOCLDWAIT; sigaction(SIGCHLD, &act, 0); - - s = socket_local_server("android:debuggerd", + + s = socket_local_server("android:debuggerd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if(s < 0) return -1; fcntl(s, F_SETFD, FD_CLOEXEC); LOG("debuggerd: " __DATE__ " " __TIME__ "\n"); - + for(;;) { struct sockaddr addr; socklen_t alen; int fd; - + alen = sizeof(addr); fd = accept(s, &addr, &alen); if(fd < 0) continue; - + fcntl(fd, F_SETFD, FD_CLOEXEC); handle_crashing_process(fd); diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 850e10b96c8..c81222a823c 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -147,9 +147,11 @@ void *load_file(const char *fn, unsigned *_sz) int match_fastboot(usb_ifc_info *info) { if(!(vendor_id && (info->dev_vendor == vendor_id)) && - (info->dev_vendor != 0x18d1) && + (info->dev_vendor != 0x18d1) && // Google (info->dev_vendor != 0x0451) && - (info->dev_vendor != 0x0bb4)) return -1; + (info->dev_vendor != 0x22b8) && // Motorola + (info->dev_vendor != 0x0bb4)) // HTC + return -1; if(info->ifc_class != 0xff) return -1; if(info->ifc_subclass != 0x42) return -1; if(info->ifc_protocol != 0x03) return -1; diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index 06c62b84c7a..3b40ba7f9ef 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -51,7 +51,9 @@ #include "usb.h" -#if TRACE_USB +#define MAX_RETRIES 5 + +#ifdef TRACE_USB #define DBG1(x...) fprintf(stderr, x) #define DBG(x...) fprintf(stderr, x) #else @@ -303,7 +305,7 @@ int usb_read(usb_handle *h, void *_data, int len) unsigned char *data = (unsigned char*) _data; unsigned count = 0; struct usbdevfs_bulktransfer bulk; - int n; + int n, retry; if(h->ep_in == 0) { return -1; @@ -316,16 +318,20 @@ int usb_read(usb_handle *h, void *_data, int len) bulk.len = xfer; bulk.data = data; bulk.timeout = 0; - - DBG("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname); - n = ioctl(h->desc, USBDEVFS_BULK, &bulk); - DBG("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname); - - if(n < 0) { - DBG1("ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); - return -1; + retry = 0; + + do{ + DBG("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname); + n = ioctl(h->desc, USBDEVFS_BULK, &bulk); + DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, h->fname, retry); + + if( n < 0 ) { + DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno)); + if ( ++retry > MAX_RETRIES ) return -1; + sleep( 1 ); + } } + while( n < 0 ); count += n; len -= n; diff --git a/fastboot/util_osx.c b/fastboot/util_osx.c index 068241cef88..b43e316d0ca 100644 --- a/fastboot/util_osx.c +++ b/fastboot/util_osx.c @@ -26,7 +26,6 @@ * SUCH DAMAGE. */ -#include #import #include diff --git a/include/acc/acc.h b/include/acc/acc.h new file mode 100644 index 00000000000..1182355281c --- /dev/null +++ b/include/acc/acc.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ACC_ACC_H +#define ANDROID_ACC_ACC_H + +#include +#include + +typedef char ACCchar; +typedef int32_t ACCint; +typedef uint32_t ACCuint; +typedef ssize_t ACCsizei; +typedef unsigned int ACCenum; +typedef void ACCvoid; +typedef struct ACCscript ACCscript; + +#define ACC_NO_ERROR 0x0000 +#define ACC_INVALID_ENUM 0x0500 +#define ACC_INVALID_OPERATION 0x0502 +#define ACC_INVALID_VALUE 0x0501 +#define ACC_OUT_OF_MEMORY 0x0505 + +#define ACC_COMPILE_STATUS 0x8B81 +#define ACC_INFO_LOG_LENGTH 0x8B84 + + +// ---------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +ACCscript* accCreateScript(); + +void accDeleteScript(ACCscript* script); + +typedef ACCvoid* (*ACCSymbolLookupFn)(ACCvoid* pContext, const ACCchar * name); + +void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn, + ACCvoid* pContext); + +ACCenum accGetError( ACCscript* script ); + +void accScriptSource(ACCscript* script, + ACCsizei count, + const ACCchar** string, + const ACCint* length); + +void accCompileScript(ACCscript* script); + +void accGetScriptiv(ACCscript* script, + ACCenum pname, + ACCint* params); + +void accGetScriptInfoLog(ACCscript* script, + ACCsizei maxLength, + ACCsizei* length, + ACCchar* infoLog); + +void accGetScriptLabel(ACCscript* script, const ACCchar * name, + ACCvoid** address); + +void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount, + ACCsizei maxStringCount, ACCchar** strings); + +/* Used to implement disassembly */ + +void accGetProgramBinary(ACCscript* script, + ACCvoid** base, + ACCsizei* length); + +#ifdef __cplusplus +}; +#endif + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/arch/darwin-x86/AndroidConfig.h b/include/arch/darwin-x86/AndroidConfig.h index 49f04e51454..ad16e0c2626 100644 --- a/include/arch/darwin-x86/AndroidConfig.h +++ b/include/arch/darwin-x86/AndroidConfig.h @@ -15,9 +15,7 @@ */ /* - * Android config -- "Darwin". Used for PPC Mac OS X. - * - * TODO: split this into "x86" and "ppc" versions + * Android config -- "Darwin". Used for X86 Mac OS X. */ #ifndef _ANDROID_CONFIG_H #define _ANDROID_CONFIG_H @@ -257,4 +255,19 @@ */ #define HAVE_WRITEV 1 +/* + * Define if exists. + */ +#define HAVE_STDINT_H 1 + +/* + * Define if exists. + */ +#define HAVE_STDBOOL_H 1 + +/* + * Define if exists. + */ +#define HAVE_SCHED_H 1 + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h new file mode 100644 index 00000000000..39c564b93a2 --- /dev/null +++ b/include/arch/freebsd-x86/AndroidConfig.h @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Android config -- "FreeBSD". Used for desktop x86 FreeBSD. + */ +#ifndef _ANDROID_CONFIG_H +#define _ANDROID_CONFIG_H + +/* + * make sure we are building for FreeBSD + */ +#ifndef OS_FREEBSD +#define OS_FREEBSD +#endif +/* + * =========================================================================== + * !!! IMPORTANT !!! + * =========================================================================== + * + * This file is included by ALL C/C++ source files. Don't put anything in + * here unless you are absolutely certain it can't go anywhere else. + * + * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//" + * comments. + */ + +/* + * Threading model. Choose one: + * + * HAVE_PTHREADS - use the pthreads library. + * HAVE_WIN32_THREADS - use Win32 thread primitives. + * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX + */ +#define HAVE_PTHREADS + +/* + * Do we have the futex syscall? + */ +/* #define HAVE_FUTEX */ + +/* + * Process creation model. Choose one: + * + * HAVE_FORKEXEC - use fork() and exec() + * HAVE_WIN32_PROC - use CreateProcess() + */ +#define HAVE_FORKEXEC + +/* + * Process out-of-memory adjustment. Set if running on Linux, + * where we can write to /proc//oom_adj to modify the out-of-memory + * badness adjustment. + */ +/* #define HAVE_OOM_ADJ */ + +/* + * IPC model. Choose one: + * + * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget). + * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap). + * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping). + * HAVE_ANDROID_IPC - use Android versions (?, mmap). + */ +#define HAVE_SYSV_IPC + +/* + * Memory-mapping model. Choose one: + * + * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h + * HAVE_WIN32_FILEMAP - use Win32 filemaps + */ +#define HAVE_POSIX_FILEMAP + +/* + * Define this if you have + */ +/* #define HAVE_TERMIO_H */ + +/* + * Define this if you build against MSVCRT.DLL + */ +/* #define HAVE_MS_C_RUNTIME */ + +/* + * Define this if you have sys/uio.h + */ +#define HAVE_SYS_UIO_H + +/* + * Define this if your platforms implements symbolic links + * in its filesystems + */ +#define HAVE_SYMLINKS + +/* + * Define this if we have localtime_r(). + */ +#define HAVE_LOCALTIME_R + +/* + * Define this if we have gethostbyname_r(). + */ +/* #define HAVE_GETHOSTBYNAME_R */ + +/* + * Define this if we have ioctl(). + */ +#define HAVE_IOCTL + +/* + * Define this if we want to use WinSock. + */ +/* #define HAVE_WINSOCK */ + +/* + * Define this if have clock_gettime() and friends + * + * Desktop Linux has this in librt, but it's broken in goobuntu, yielding + * mildly or wildly inaccurate results. + */ +#define HAVE_POSIX_CLOCKS + +/* + * Define this if we have pthread_cond_timedwait_monotonic() and + * clock_gettime(CLOCK_MONOTONIC). + */ +/* #define HAVE_TIMEDWAIT_MONOTONIC */ + +/* + * Define this if we have linux style epoll() + */ +/* #define HAVE_EPOLL */ + +/* + * Endianness of the target machine. Choose one: + * + * HAVE_ENDIAN_H -- have endian.h header we can include. + * HAVE_LITTLE_ENDIAN -- we are little endian. + * HAVE_BIG_ENDIAN -- we are big endian. + */ +/* #define HAVE_ENDIAN_H */ +#define HAVE_LITTLE_ENDIAN + +/* + * Define this if you have sys/endian.h + * NOTE: mutually exclusive with HAVE_ENDIAN_H + */ +#define HAVE_SYS_ENDIAN_H + +/* + * We need to choose between 32-bit and 64-bit off_t. All of our code should + * agree on the same size. For desktop systems, use 64-bit values, + * because some of our libraries (e.g. wxWidgets) expect to be built that way. + */ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE_SOURCE 1 + +/* + * Defined if we have the backtrace() call for retrieving a stack trace. + * Needed for CallStack to operate; if not defined, CallStack is + * non-functional. + */ +#define HAVE_BACKTRACE 0 + +/* + * Defined if we have the dladdr() call for retrieving the symbol associated + * with a memory address. If not defined, stack crawls will not have symbolic + * information. + */ +#define HAVE_DLADDR 1 + +/* + * Defined if we have the cxxabi.h header for demangling C++ symbols. If + * not defined, stack crawls will be displayed with raw mangled symbols + */ +#define HAVE_CXXABI 0 + +/* + * Defined if we have the gettid() system call. + */ +/* #define HAVE_GETTID */ + +/* + * Defined if we have the sched_setscheduler() call + */ +#define HAVE_SCHED_SETSCHEDULER + +/* + * Add any extra platform-specific defines here. + */ + +/* + * Define if we have header + */ +#define HAVE_MALLOC_H + +/* + * Define if we have Linux-style non-filesystem Unix Domain Sockets + */ + +/* + * What CPU architecture does this platform use? + */ +#define ARCH_X86 + + +/* + * Define if we have Linux's inotify in . + */ +/*#define HAVE_INOTIFY 1*/ + +/* + * Define if we have madvise() in + */ +#define HAVE_MADVISE 1 + +/* + * Define if tm struct has tm_gmtoff field + */ +#define HAVE_TM_GMTOFF 1 + +/* + * Define if dirent struct has d_type field + */ +#define HAVE_DIRENT_D_TYPE 1 + +/* + * Define if libc includes Android system properties implementation. + */ +/* #define HAVE_LIBC_SYSTEM_PROPERTIES */ + +/* + * Define if system provides a system property server (should be + * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES). + */ +#define HAVE_SYSTEM_PROPERTY_SERVER + +/* + * sprintf() format string for shared library naming. + */ +#define OS_SHARED_LIB_FORMAT_STR "lib%s.so" + +/* + * type for the third argument to mincore(). + */ +#define MINCORE_POINTER_TYPE char * + +/* + * Do we have the sigaction flag SA_NOCLDWAIT? + */ +#define HAVE_SA_NOCLDWAIT + +/* + * Define if we include for statfs() + */ +#define INCLUDE_SYS_MOUNT_FOR_STATFS 1 + +/* + * The default path separator for the platform + */ +#define OS_PATH_SEPARATOR '/' + +/* + * Is the filesystem case sensitive? + */ +#define OS_CASE_SENSITIVE + +/* + * Define if exists. + */ +#define HAVE_SYS_SOCKET_H 1 + +/* + * Define if the strlcpy() function exists on the system. + */ +#define HAVE_STRLCPY 1 + +/* + * Define if prctl() exists + */ +/* #define HAVE_PRCTL 1 */ + +/* + * Define if writev() exists + */ +#define HAVE_WRITEV 1 + +/* + * Define if does not exist + * NOTE: defines alloca() which + * on FreeBSD is defined in + */ +#define HAVE_NO_ALLOCA_H + +/* + * Defines CLOCK_PROCESS_CPUTIME_ID for clock_gettime() + * XXX: CLOCK_PROF seems to be commonly used replacement + */ +#ifndef CLOCK_PROCESS_CPUTIME_ID +#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROF +#endif + +/* + * Define if exists. + */ +/* #define HAVE_STDINT_H */ + +/* + * Define if exists. + */ +/* #define HAVE_STDBOOL_H */ + +/* + * Define if exists. + */ +#define HAVE_SCHED_H 1 + +#endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h index f3221274922..82e39c01dff 100644 --- a/include/arch/linux-arm/AndroidConfig.h +++ b/include/arch/linux-arm/AndroidConfig.h @@ -302,4 +302,19 @@ */ #define HAVE_WRITEV 1 +/* + * Define if exists. + */ +#define HAVE_STDINT_H 1 + +/* + * Define if exists. + */ +#define HAVE_STDBOOL_H 1 + +/* + * Define if exists. + */ +#define HAVE_SCHED_H 1 + #endif /* _ANDROID_CONFIG_H */ diff --git a/include/arch/linux-x86/AndroidConfig.h b/include/arch/linux-x86/AndroidConfig.h index 6de75f8d1bc..557ec5f9466 100644 --- a/include/arch/linux-x86/AndroidConfig.h +++ b/include/arch/linux-x86/AndroidConfig.h @@ -283,4 +283,19 @@ */ #define HAVE_WRITEV 1 +/* + * Define if exists. + */ +#define HAVE_STDINT_H 1 + +/* + * Define if exists. + */ +#define HAVE_STDBOOL_H 1 + +/* + * Define if exists. + */ +#define HAVE_SCHED_H 1 + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h index 4aa44f8835c..6605723291b 100644 --- a/include/arch/target_linux-x86/AndroidConfig.h +++ b/include/arch/target_linux-x86/AndroidConfig.h @@ -293,4 +293,19 @@ */ #define HAVE_UNWIND_CONTEXT_STRUCT +/* + * Define if exists. + */ +#define HAVE_STDINT_H 1 + +/* + * Define if exists. + */ +#define HAVE_STDBOOL_H 1 + +/* + * Define if exists. + */ +#define HAVE_SCHED_H 1 + #endif /* _ANDROID_CONFIG_H */ diff --git a/include/arch/windows/AndroidConfig.h b/include/arch/windows/AndroidConfig.h index c3c6ff11d84..b240519a058 100644 --- a/include/arch/windows/AndroidConfig.h +++ b/include/arch/windows/AndroidConfig.h @@ -287,4 +287,19 @@ */ /* #define HAVE_WRITEV */ +/* + * Define if exists. + */ +/* #define HAVE_STDINT_H */ + +/* + * Define if exists. + */ +/* #define HAVE_STDBOOL_H */ + +/* + * Define if exists. + */ +/* #define HAVE_SCHED_H */ + #endif /*_ANDROID_CONFIG_H*/ diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h new file mode 100644 index 00000000000..fbb1112fae7 --- /dev/null +++ b/include/cutils/abort_socket.h @@ -0,0 +1,103 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Helper to perform abortable blocking operations on a socket: + * asocket_connect() + * asocket_accept() + * asocket_read() + * asocket_write() + * These calls are similar to the regular syscalls, but can be aborted with: + * asocket_abort() + * + * Calling close() on a regular POSIX socket does not abort blocked syscalls on + * that socket in other threads. + * + * After calling asocket_abort() the socket cannot be reused. + * + * Call asocket_destory() *after* all threads have finished with the socket to + * finish closing the socket and free the asocket structure. + * + * The helper is implemented by setting the socket non-blocking to initiate + * syscalls connect(), accept(), read(), write(), then using a blocking poll() + * on both the primary socket and a local pipe. This makes the poll() abortable + * by writing a byte to the local pipe in asocket_abort(). + * + * asocket_create() sets the fd to non-blocking mode. It must not be changed to + * blocking mode. + * + * Using asocket will triple the number of file descriptors required per + * socket, due to the local pipe. It may be possible to use a global pipe per + * process rather than per socket, but we have not been able to come up with a + * race-free implementation yet. + * + * All functions except asocket_init() and asocket_destroy() are thread safe. + */ + +#include +#include + +#ifndef __CUTILS_ABORT_SOCKET_H__ +#define __CUTILS_ABORT_SOCKET_H__ +#ifdef __cplusplus +extern "C" { +#endif + +struct asocket { + int fd; /* primary socket fd */ + int abort_fd[2]; /* pipe used to abort */ +}; + +/* Create an asocket from fd. + * Sets the socket to non-blocking mode. + * Returns NULL on error with errno set. + */ +struct asocket *asocket_init(int fd); + +/* Blocking socket I/O with timeout. + * Calling asocket_abort() from another thread will cause each of these + * functions to immediately return with value -1 and errno ECANCELED. + * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned + * with errno ETIMEDOUT. + * EINTR is handled in-call. + * Other semantics are identical to the regular syscalls. + */ +int asocket_connect(struct asocket *s, const struct sockaddr *addr, + socklen_t addrlen, int timeout); + +int asocket_accept(struct asocket *s, struct sockaddr *addr, + socklen_t *addrlen, int timeout); + +int asocket_read(struct asocket *s, void *buf, size_t count, int timeout); + +int asocket_write(struct asocket *s, const void *buf, size_t count, + int timeout); + +/* Abort above calls and shutdown socket. + * Further I/O operations on this socket will immediately fail after this call. + * asocket_destroy() should be used to release resources once all threads + * have returned from blocking calls on the socket. + */ +void asocket_abort(struct asocket *s); + +/* Close socket and free asocket structure. + * Must not be called until all calls on this structure have completed. + */ +void asocket_destroy(struct asocket *s); + +#ifdef __cplusplus +} +#endif +#endif //__CUTILS_ABORT_SOCKET__H__ diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h index 0683bf2553e..fd56dbef344 100644 --- a/include/cutils/ashmem.h +++ b/include/cutils/ashmem.h @@ -10,6 +10,8 @@ #ifndef _CUTILS_ASHMEM_H #define _CUTILS_ASHMEM_H +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/include/cutils/compiler.h b/include/cutils/compiler.h new file mode 100644 index 00000000000..09112d5ac67 --- /dev/null +++ b/include/cutils/compiler.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CUTILS_COMPILER_H +#define ANDROID_CUTILS_COMPILER_H + +/* + * helps the compiler's optimizer predicting branches + */ + +#ifdef __cplusplus +# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) +#else +# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) +# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) +#endif + +#endif // ANDROID_CUTILS_COMPILER_H diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h new file mode 100644 index 00000000000..eaf39939aeb --- /dev/null +++ b/include/cutils/sched_policy.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_SCHED_POLICY_H +#define __CUTILS_SCHED_POLICY_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SP_BACKGROUND = 0, + SP_FOREGROUND = 1, +} SchedPolicy; + +extern int set_sched_policy(int tid, SchedPolicy policy); +extern int get_sched_policy(int tid, SchedPolicy *policy); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_SCHED_POLICY_H */ diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h index 69dbc8812ef..cf103cae5ec 100644 --- a/include/cutils/tztime.h +++ b/include/cutils/tztime.h @@ -17,6 +17,8 @@ #ifndef _CUTILS_TZTIME_H #define _CUTILS_TZTIME_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -24,6 +26,9 @@ extern "C" { time_t mktime_tz(struct tm * const tmp, char const * tz); void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz); +#ifndef HAVE_ANDROID_OS +/* the following is defined in in Bionic */ + struct strftime_locale { const char *mon[12]; /* short names */ const char *month[12]; /* long names */ @@ -40,6 +45,8 @@ struct strftime_locale { size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale); +#endif /* !HAVE_ANDROID_OS */ + #ifdef __cplusplus } #endif diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h index c52346066bb..af63e8775e7 100644 --- a/include/mincrypt/sha.h +++ b/include/mincrypt/sha.h @@ -13,14 +13,14 @@ ** be used to endorse or promote products derived from this software ** without specific prior written permission. ** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR +** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -36,16 +36,23 @@ extern "C" { typedef struct SHA_CTX { uint64_t count; - uint8_t buf[64]; uint32_t state[5]; +#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) + union { + uint8_t b[64]; + uint32_t w[16]; + } buf; +#else + uint8_t buf[64]; +#endif } SHA_CTX; -void SHA_init(SHA_CTX *ctx); -void SHA_update(SHA_CTX *ctx, const void* data, int len); -const uint8_t* SHA_final(SHA_CTX *ctx); +void SHA_init(SHA_CTX* ctx); +void SHA_update(SHA_CTX* ctx, const void* data, int len); +const uint8_t* SHA_final(SHA_CTX* ctx); /* Convenience method. Returns digest parameter value. */ -const uint8_t* SHA(const void *data, int len, uint8_t *digest); +const uint8_t* SHA(const void* data, int len, uint8_t* digest); #define SHA_DIGEST_SIZE 20 diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 6ba574b12e3..24b7c819abf 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -156,10 +156,10 @@ static struct fs_path_config android_files[] = { { 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" }, { 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" }, { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" }, - { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/hcid.conf" }, + { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/main.conf" }, { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" }, { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" }, - { 00440, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" }, + { 00444, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" }, { 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" }, { 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" }, { 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" }, diff --git a/include/private/pixelflinger/ggl_context.h b/include/private/pixelflinger/ggl_context.h index 3a030c526b3..8a36fa9ee23 100644 --- a/include/private/pixelflinger/ggl_context.h +++ b/include/private/pixelflinger/ggl_context.h @@ -21,8 +21,8 @@ #include #include #include +#include -#include #include #include diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h index 68dcb8f4592..c7edfeb0076 100644 --- a/include/sysutils/SocketListener.h +++ b/include/sysutils/SocketListener.h @@ -33,7 +33,7 @@ class SocketListener { SocketListener(const char *socketNames, bool listen); SocketListener(int socketFd, bool listen); - virtual ~SocketListener() {} + virtual ~SocketListener(); int startListener(); int stopListener(); diff --git a/init/builtins.c b/init/builtins.c index 17df0af5c84..5a1b2637895 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "init.h" #include "keywords.h" @@ -48,7 +49,7 @@ static int write_file(const char *path, const char *value) fd = open(path, O_WRONLY|O_CREAT, 0622); if (fd < 0) - return -1; + return -errno; len = strlen(value); @@ -58,7 +59,7 @@ static int write_file(const char *path, const char *value) close(fd); if (ret < 0) { - return -1; + return -errno; } else { return 0; } @@ -257,7 +258,7 @@ static struct { int do_mount(int nargs, char **args) { char tmp[64]; - char *source; + char *source, *target, *system; char *options = NULL; unsigned flags = 0; int n, i; @@ -275,15 +276,70 @@ int do_mount(int nargs, char **args) options = args[n]; } + system = args[1]; source = args[2]; + target = args[3]; + if (!strncmp(source, "mtd@", 4)) { n = mtd_name_to_number(source + 4); - if (n >= 0) { - sprintf(tmp, "/dev/block/mtdblock%d", n); - source = tmp; + if (n < 0) { + return -1; } + + sprintf(tmp, "/dev/block/mtdblock%d", n); + + if (mount(tmp, target, system, flags, options) < 0) { + return -1; + } + + return 0; + } else if (!strncmp(source, "loop@", 5)) { + int mode, loop, fd; + struct loop_info info; + + mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; + fd = open(source + 5, mode); + if (fd < 0) { + return -1; + } + + for (n = 0; ; n++) { + sprintf(tmp, "/dev/block/loop%d", n); + loop = open(tmp, mode); + if (loop < 0) { + return -1; + } + + /* if it is a blank loop device */ + if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { + /* if it becomes our loop device */ + if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { + close(fd); + + if (mount(tmp, target, system, flags, options) < 0) { + ioctl(loop, LOOP_CLR_FD, 0); + close(loop); + return -1; + } + + close(loop); + return 0; + } + } + + close(loop); + } + + close(fd); + ERROR("out of loopback devices"); + return -1; + } else { + if (mount(source, target, system, flags, options) < 0) { + return -1; + } + + return 0; } - return mount(source, args[3], args[1], flags, options); } int do_setkey(int nargs, char **args) @@ -371,6 +427,68 @@ int do_write(int nargs, char **args) return write_file(args[1], args[2]); } +int do_copy(int nargs, char **args) +{ + char *buffer = NULL; + int rc = 0; + int fd1 = -1, fd2 = -1; + struct stat info; + int brtw, brtr; + char *p; + + if (nargs != 3) + return -1; + + if (stat(args[1], &info) < 0) + return -1; + + if ((fd1 = open(args[1], O_RDONLY)) < 0) + goto out_err; + + if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0) + goto out_err; + + if (!(buffer = malloc(info.st_size))) + goto out_err; + + p = buffer; + brtr = info.st_size; + while(brtr) { + rc = read(fd1, p, brtr); + if (rc < 0) + goto out_err; + if (rc == 0) + break; + p += rc; + brtr -= rc; + } + + p = buffer; + brtw = info.st_size; + while(brtw) { + rc = write(fd2, p, brtw); + if (rc < 0) + goto out_err; + if (rc == 0) + break; + p += rc; + brtw -= rc; + } + + rc = 0; + goto out; +out_err: + rc = -1; +out: + if (buffer) + free(buffer); + if (fd1 >= 0) + close(fd1); + if (fd2 >= 0) + close(fd2); + return rc; +} + int do_chown(int nargs, char **args) { /* GID is optional. */ if (nargs == 3) { diff --git a/init/devices.c b/init/devices.c index ac72b345ded..ea1a825c5ba 100644 --- a/init/devices.c +++ b/init/devices.c @@ -95,21 +95,28 @@ static struct perms_ devperms[] = { /* logger should be world writable (for logging) but not readable */ { "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 }, + /* the msm hw3d client device node is world writable/readable. */ + { "/dev/msm_hw3dc", 0666, AID_ROOT, AID_ROOT, 0 }, + + /* gpu driver for adreno200 is globally accessible */ + { "/dev/kgsl", 0666, AID_ROOT, AID_ROOT, 0 }, + /* these should not be world writable */ + { "/dev/diag", 0660, AID_RADIO, AID_RADIO, 0 }, + { "/dev/diag_arm9", 0660, AID_RADIO, AID_RADIO, 0 }, { "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 }, { "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 }, { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, - { "/dev/uinput", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, + { "/dev/uinput", 0660, AID_SYSTEM, AID_BLUETOOTH, 0 }, { "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 }, { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 }, { "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 }, - { "/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, + { "/dev/msm_hw3dm", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, { "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 }, { "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 }, { "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 }, { "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, - { "/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 }, { "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 }, { "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 }, @@ -118,20 +125,34 @@ static struct perms_ devperms[] = { { "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 }, { "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, { "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, + { "/dev/akm8973_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, + { "/dev/akm8973_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, + { "/dev/bma150", 0640, AID_COMPASS, AID_SYSTEM, 0 }, + { "/dev/cm3602", 0640, AID_COMPASS, AID_SYSTEM, 0 }, { "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 }, + { "/dev/lightsensor", 0640, AID_SYSTEM, AID_SYSTEM, 0 }, { "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 }, + { "/dev/audience_a1026", 0660, AID_SYSTEM, AID_AUDIO, 1 }, { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/msm_audio_ctl", 0660, AID_SYSTEM, AID_AUDIO, 0 }, { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/vdec", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/q6venc", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/snd/dsp", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/snd/dsp1", 0660, AID_SYSTEM, AID_AUDIO, 0 }, + { "/dev/snd/mixer", 0660, AID_SYSTEM, AID_AUDIO, 0 }, { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 }, { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, + /* CDMA radio interface MUX */ + { "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 }, { "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 }, { "/dev/tun", 0640, AID_VPN, AID_VPN, 0 }, { NULL, 0, 0, 0, 0 }, @@ -393,6 +414,9 @@ static void handle_device_event(struct uevent *uevent) } else if(!strncmp(uevent->subsystem, "mtd", 3)) { base = "/dev/mtd/"; mkdir(base, 0755); + } else if(!strncmp(uevent->subsystem, "sound", 5)) { + base = "/dev/snd/"; + mkdir(base, 0755); } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) { base = "/dev/log/"; diff --git a/init/init.c b/init/init.c index 0c1ad3fa660..8c2a0582e4b 100644 --- a/init/init.c +++ b/init/init.c @@ -255,9 +255,11 @@ void service_start(struct service *svc, const char *dynamic_args) setuid(svc->uid); } - if (!dynamic_args) - execve(svc->args[0], (char**) svc->args, (char**) ENV); - else { + if (!dynamic_args) { + if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { + ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); + } + } else { char *arg_ptrs[SVC_MAXARGS+1]; int arg_idx = svc->nargs; char *tmp = strdup(dynamic_args); diff --git a/init/keywords.h b/init/keywords.h index 6f47379c615..641426cafd0 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -21,6 +21,7 @@ int do_trigger(int nargs, char **args); int do_symlink(int nargs, char **args); int do_sysclktz(int nargs, char **args); int do_write(int nargs, char **args); +int do_copy(int nargs, char **args); int do_chown(int nargs, char **args); int do_chmod(int nargs, char **args); int do_loglevel(int nargs, char **args); @@ -65,6 +66,7 @@ enum { KEYWORD(sysclktz, COMMAND, 1, do_sysclktz) KEYWORD(user, OPTION, 0, 0) KEYWORD(write, COMMAND, 2, do_write) + KEYWORD(copy, COMMAND, 2, do_copy) KEYWORD(chown, COMMAND, 2, do_chown) KEYWORD(chmod, COMMAND, 2, do_chmod) KEYWORD(loglevel, COMMAND, 1, do_loglevel) diff --git a/init/parser.c b/init/parser.c index 33c1a6813e6..affc80c9aa8 100644 --- a/init/parser.c +++ b/init/parser.c @@ -127,6 +127,7 @@ int lookup_keyword(const char *s) { switch (*s++) { case 'c': + if (!strcmp(s, "opy")) return K_copy; if (!strcmp(s, "apability")) return K_capability; if (!strcmp(s, "lass")) return K_class; if (!strcmp(s, "lass_start")) return K_class_start; diff --git a/init/property_service.c b/init/property_service.c index 23a8821d004..7db7c2cbf17 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -52,29 +52,32 @@ static int persistent_properties_loaded = 0; struct { const char *prefix; unsigned int uid; + unsigned int gid; } property_perms[] = { - { "net.rmnet0.", AID_RADIO }, - { "net.gprs.", AID_RADIO }, - { "ril.", AID_RADIO }, - { "gsm.", AID_RADIO }, - { "net.dns", AID_RADIO }, - { "net.", AID_SYSTEM }, - { "dev.", AID_SYSTEM }, - { "runtime.", AID_SYSTEM }, - { "hw.", AID_SYSTEM }, - { "sys.", AID_SYSTEM }, - { "service.", AID_SYSTEM }, - { "wlan.", AID_SYSTEM }, - { "dhcp.", AID_SYSTEM }, - { "dhcp.", AID_DHCP }, - { "vpn.", AID_SYSTEM }, - { "vpn.", AID_VPN }, - { "debug.", AID_SHELL }, - { "log.", AID_SHELL }, - { "service.adb.root", AID_SHELL }, - { "persist.sys.", AID_SYSTEM }, - { "persist.service.", AID_SYSTEM }, - { NULL, 0 } + { "net.rmnet0.", AID_RADIO, 0 }, + { "net.gprs.", AID_RADIO, 0 }, + { "net.ppp", AID_RADIO, 0 }, + { "ril.", AID_RADIO, 0 }, + { "gsm.", AID_RADIO, 0 }, + { "persist.radio", AID_RADIO, 0 }, + { "net.dns", AID_RADIO, 0 }, + { "net.", AID_SYSTEM, 0 }, + { "dev.", AID_SYSTEM, 0 }, + { "runtime.", AID_SYSTEM, 0 }, + { "hw.", AID_SYSTEM, 0 }, + { "sys.", AID_SYSTEM, 0 }, + { "service.", AID_SYSTEM, 0 }, + { "wlan.", AID_SYSTEM, 0 }, + { "dhcp.", AID_SYSTEM, 0 }, + { "dhcp.", AID_DHCP, 0 }, + { "vpn.", AID_SYSTEM, 0 }, + { "vpn.", AID_VPN, 0 }, + { "debug.", AID_SHELL, 0 }, + { "log.", AID_SHELL, 0 }, + { "service.adb.root", AID_SHELL, 0 }, + { "persist.sys.", AID_SYSTEM, 0 }, + { "persist.service.", AID_SYSTEM, 0 }, + { NULL, 0, 0 } }; /* @@ -84,8 +87,10 @@ struct { struct { const char *service; unsigned int uid; + unsigned int gid; } control_perms[] = { - {NULL, 0 } + { "dumpstate",AID_SHELL, AID_LOG }, + {NULL, 0, 0 } }; typedef struct { @@ -181,7 +186,7 @@ static int property_write(prop_info *pi, const char *value) * * Returns 1 if uid allowed, 0 otherwise. */ -static int check_control_perms(const char *name, int uid) { +static int check_control_perms(const char *name, int uid, int gid) { int i; if (uid == AID_SYSTEM || uid == AID_ROOT) return 1; @@ -189,8 +194,10 @@ static int check_control_perms(const char *name, int uid) { /* Search the ACL */ for (i = 0; control_perms[i].service; i++) { if (strcmp(control_perms[i].service, name) == 0) { - if (control_perms[i].uid == uid) + if ((uid && control_perms[i].uid == uid) || + (gid && control_perms[i].gid == gid)) { return 1; + } } } return 0; @@ -200,7 +207,7 @@ static int check_control_perms(const char *name, int uid) { * Checks permissions for setting system properties. * Returns 1 if uid allowed, 0 otherwise. */ -static int check_perms(const char *name, unsigned int uid) +static int check_perms(const char *name, unsigned int uid, int gid) { int i; if (uid == 0) @@ -213,7 +220,8 @@ static int check_perms(const char *name, unsigned int uid) int tmp; if (strncmp(property_perms[i].prefix, name, strlen(property_perms[i].prefix)) == 0) { - if (property_perms[i].uid == uid) { + if ((uid && property_perms[i].uid == uid) || + (gid && property_perms[i].gid == gid)) { return 1; } } @@ -237,7 +245,7 @@ const char* property_get(const char *name) } } -static void write_peristent_property(const char *name, const char *value) +static void write_persistent_property(const char *name, const char *value) { const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp"; char path[PATH_MAX]; @@ -248,7 +256,7 @@ static void write_peristent_property(const char *name, const char *value) fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd < 0) { ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno); - return; + return; } write(fd, value, strlen(value)); close(fd); @@ -302,7 +310,7 @@ int property_set(const char *name, const char *value) if (strcmp("net.change", name) == 0) { return 0; } - /* + /* * The 'net.change' property is a special property used track when any * 'net.*' property name is updated. It is _ONLY_ updated here. Its value * contains the last updated 'net.*' property. @@ -310,11 +318,11 @@ int property_set(const char *name, const char *value) property_set("net.change", name); } else if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) { - /* + /* * Don't write properties to disk until after we have read all default properties * to prevent them from being overwritten by default values. */ - write_peristent_property(name, value); + write_persistent_property(name, value); } property_changed(name, value); return 0; @@ -371,14 +379,14 @@ void handle_property_set_fd(int fd) msg.value[PROP_VALUE_MAX-1] = 0; if(memcmp(msg.name,"ctl.",4) == 0) { - if (check_control_perms(msg.value, cr.uid)) { + if (check_control_perms(msg.value, cr.uid, cr.gid)) { handle_control_message((char*) msg.name + 4, (char*) msg.value); } else { ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n", msg.name + 4, msg.value, cr.uid, cr.pid); } } else { - if (check_perms(msg.name, cr.uid)) { + if (check_perms(msg.name, cr.uid, cr.gid)) { property_set((char*) msg.name, (char*) msg.value); } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", @@ -474,7 +482,7 @@ static void load_persistent_properties() } else { ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno); } - + persistent_properties_loaded = 1; } diff --git a/libacc/Android.mk b/libacc/Android.mk new file mode 100644 index 00000000000..2b4998e5902 --- /dev/null +++ b/libacc/Android.mk @@ -0,0 +1,31 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# Shared library for target +# ======================================================== + +LOCAL_MODULE:= libacc +LOCAL_SRC_FILES := acc.cpp + +LOCAL_SHARED_LIBRARIES := libdl libcutils + +include $(BUILD_SHARED_LIBRARY) + +# Shared library for host +# ======================================================== + +include $(CLEAR_VARS) +LOCAL_MODULE:= libacc +LOCAL_SRC_FILES := acc.cpp + +LOCAL_CFLAGS := -O0 -g + +LOCAL_STATIC_LIBRARIES := libcutils +LOCAL_LDLIBS := -ldl + +include $(BUILD_HOST_SHARED_LIBRARY) + +# Build children +# ======================================================== + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libacc/FEATURES b/libacc/FEATURES new file mode 100644 index 00000000000..97a876d9e35 --- /dev/null +++ b/libacc/FEATURES @@ -0,0 +1,83 @@ + +Supported C language subset: + + - Expressions: + + * binary operators, by decreasing priority order: '*' '/' '%', + '+' '-', '>>' '<<', '<' '<=' '>' '>=', '==' '!=', '&', + '^', '|', '=', '&&', '||'. + + * '&&' and '||' have the same semantics as C : left to right + evaluation and early exit. + + * Parenthesis are supported. + + * Comma operator is supported. + + * Trinary operator (?:) is not supported. + + * Unary operators: '&', '*' (pointer indirection), '-' + (negation), '+', '!', '~', '++' and '--'. + + * Pointer indirection ('*') is supported. + + * Square brackets can be used for pointer arithmetic. + + * '=' and = are supported. + + * Function calls are supported with standard Linux calling + convention. Function pointers are supported. + Functions can be used before being declared. + + - sizeof() is not supported. + + - Types: + + int, short, char, float, double + + pointers + + variables can be initialized in declarations. + + Only ANSI-style function declarations are supported. + - "..." is not supported. + - short is not supported + - const is not supported + - arrays are not supported + - long doubles are not supported + - structs are not supported + + - Unknown functions and variables are bound at compile time by calling + back to the caller. For the 'acc' command-line tool unknown functions + and variables are looked up using dlsym, to allow using many libc + functions and variables. + + - Instructions: blocks ('{' '}') are supported as in C. 'if' and + 'else' can be used for tests. The 'while' and 'for' C constructs + are supported for loops. 'break' can be used to exit + loops. 'return' is used for the return value of a function. + + - switch / case is not supported. + - goto and labels are not supported. + - continue is not supported. + + - Identifiers are parsed the same way as C. Local variables are + handled, but there is no local name space (not a problem if + different names are used for local and global variables). + + - Numbers can be entered in decimal, hexadecimal ('0x' or '0X' + prefix), or octal ('0' prefix). + + - Float and double constants are supported. + + - '#define' is supported without function like arguments. No macro + recursion is tolerated. Other preprocessor directives are + ignored. + + - C Strings and C character constants are supported. All ANSI C + character escapes are supported. + + - Both C comments ( /* */ ) and C++ comments ( // ... end-of-line ) are + supported. + + - Some syntax errors are reported, others may cause a crash. + + - Memory: the code, data, and symbol sizes are limited to 100KB + (it can be changed in the source code). + diff --git a/libacc/LICENSE b/libacc/LICENSE new file mode 100644 index 00000000000..aea41e08654 --- /dev/null +++ b/libacc/LICENSE @@ -0,0 +1,21 @@ + Obfuscated Tiny C Compiler + + Copyright (C) 2001-2003 Fabrice Bellard + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product and its documentation + *is* required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + diff --git a/libacc/MODULE_LICENSE_BSD_LIKE b/libacc/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libacc/acc.cpp b/libacc/acc.cpp new file mode 100644 index 00000000000..808752e3070 --- /dev/null +++ b/libacc/acc.cpp @@ -0,0 +1,6241 @@ +/* + * Android "Almost" C Compiler. + * This is a compiler for a small subset of the C language, intended for use + * in scripting environments where speed and memory footprint are important. + * + * This code is based upon the "unobfuscated" version of the + * Obfuscated Tiny C compiler, see the file LICENSE for details. + * + */ + +#define LOG_TAG "acc" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(__i386__) +#include +#endif + + +#if defined(__arm__) +#define DEFAULT_ARM_CODEGEN +#define PROVIDE_ARM_CODEGEN +#elif defined(__i386__) +#define DEFAULT_X86_CODEGEN +#define PROVIDE_X86_CODEGEN +#elif defined(__x86_64__) +#define DEFAULT_X64_CODEGEN +#define PROVIDE_X64_CODEGEN +#endif + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) +#define ARM_USE_VFP +#endif + +#include + +#define LOG_API(...) do {} while(0) +// #define LOG_API(...) fprintf (stderr, __VA_ARGS__) + +#define LOG_STACK(...) do {} while(0) +// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__) + +// #define PROVIDE_TRACE_CODEGEN + +// Uncomment to disable ARM peephole optimizations +// #define DISABLE_ARM_PEEPHOLE + +// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN +// #define DEBUG_SAVE_INPUT_TO_FILE + +#ifdef DEBUG_SAVE_INPUT_TO_FILE +#ifdef ARM_USE_VFP +#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c" +#else +#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c" +#endif +#endif + +#define assert(b) assertImpl(b, __LINE__) + +namespace acc { + +// Subset of STL vector. +template class Vector { + public: + Vector() { + mpBase = 0; + mUsed = 0; + mSize = 0; + } + + ~Vector() { + if (mpBase) { + for(size_t i = 0; i < mUsed; i++) { + mpBase[mUsed].~E(); + } + free(mpBase); + } + } + + inline E& operator[](size_t i) { + return mpBase[i]; + } + + inline E& front() { + return mpBase[0]; + } + + inline E& back() { + return mpBase[mUsed - 1]; + } + + void pop_back() { + mUsed -= 1; + mpBase[mUsed].~E(); + } + + void push_back(const E& item) { + * ensure(1) = item; + } + + size_t size() { + return mUsed; + } + +private: + E* ensure(int n) { + size_t newUsed = mUsed + n; + if (newUsed > mSize) { + size_t newSize = mSize * 2 + 10; + if (newSize < newUsed) { + newSize = newUsed; + } + mpBase = (E*) realloc(mpBase, sizeof(E) * newSize); + mSize = newSize; + } + E* result = mpBase + mUsed; + mUsed = newUsed; + return result; + } + + E* mpBase; + size_t mUsed; + size_t mSize; +}; + +class ErrorSink { +public: + void error(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + verror(fmt, ap); + va_end(ap); + } + + virtual ~ErrorSink() {} + virtual void verror(const char* fmt, va_list ap) = 0; +}; + +class Compiler : public ErrorSink { + typedef int tokenid_t; + enum TypeTag { + TY_INT, // 0 + TY_CHAR, // 1 + TY_SHORT, // 2 + TY_VOID, // 3 + TY_FLOAT, // 4 + TY_DOUBLE, // 5 + TY_POINTER, // 6 + TY_ARRAY, // 7 + TY_STRUCT, // 8 + TY_FUNC, // 9 + TY_PARAM // 10 + }; + + struct Type { + TypeTag tag; + tokenid_t id; // For function arguments, global vars, local vars, struct elements + tokenid_t structTag; // For structs the name of the struct + int length; // length of array, offset of struct element. -1 means struct is forward defined + int alignment; // for structs only + Type* pHead; // For a struct this is the prototype struct. + Type* pTail; + }; + + enum ExpressionType { + ET_RVALUE, + ET_LVALUE + }; + + struct ExpressionValue { + ExpressionValue() { + et = ET_RVALUE; + pType = NULL; + } + ExpressionType et; + Type* pType; + }; + + class ICodeBuf { + public: + virtual ~ICodeBuf() {} + virtual void init(int size) = 0; + virtual void setErrorSink(ErrorSink* pErrorSink) = 0; + virtual void o4(int n) = 0; + virtual void ob(int n) = 0; + virtual void* getBase() = 0; + virtual intptr_t getSize() = 0; + virtual intptr_t getPC() = 0; + // Call this before trying to modify code in the buffer. + virtual void flush() = 0; + }; + + class CodeBuf : public ICodeBuf { + char* ind; // Output code pointer + char* pProgramBase; + ErrorSink* mErrorSink; + int mSize; + bool mOverflowed; + + void release() { + if (pProgramBase != 0) { + free(pProgramBase); + pProgramBase = 0; + } + } + + bool check(int n) { + int newSize = ind - pProgramBase + n; + bool overflow = newSize > mSize; + if (overflow && !mOverflowed) { + mOverflowed = true; + if (mErrorSink) { + mErrorSink->error("Code too large: %d bytes", newSize); + } + } + return overflow; + } + + public: + CodeBuf() { + pProgramBase = 0; + ind = 0; + mErrorSink = 0; + mSize = 0; + mOverflowed = false; + } + + virtual ~CodeBuf() { + release(); + } + + virtual void init(int size) { + release(); + mSize = size; + pProgramBase = (char*) calloc(1, size); + ind = pProgramBase; + } + + virtual void setErrorSink(ErrorSink* pErrorSink) { + mErrorSink = pErrorSink; + } + + virtual void o4(int n) { + if(check(4)) { + return; + } + * (int*) ind = n; + ind += 4; + } + + /* + * Output a byte. Handles all values, 0..ff. + */ + virtual void ob(int n) { + if(check(1)) { + return; + } + *ind++ = n; + } + + virtual void* getBase() { + return (void*) pProgramBase; + } + + virtual intptr_t getSize() { + return ind - pProgramBase; + } + + virtual intptr_t getPC() { + return (intptr_t) ind; + } + + virtual void flush() {} + }; + + /** + * A code generator creates an in-memory program, generating the code on + * the fly. There is one code generator implementation for each supported + * architecture. + * + * The code generator implements the following abstract machine: + * R0 - the accumulator. + * FP - a frame pointer for accessing function arguments and local + * variables. + * SP - a stack pointer for storing intermediate results while evaluating + * expressions. The stack pointer grows downwards. + * + * The function calling convention is that all arguments are placed on the + * stack such that the first argument has the lowest address. + * After the call, the result is in R0. The caller is responsible for + * removing the arguments from the stack. + * The R0 register is not saved across function calls. The + * FP and SP registers are saved. + */ + + class CodeGenerator { + public: + CodeGenerator() { + mErrorSink = 0; + pCodeBuf = 0; + pushType(); + } + virtual ~CodeGenerator() {} + + virtual void init(ICodeBuf* pCodeBuf) { + this->pCodeBuf = pCodeBuf; + pCodeBuf->setErrorSink(mErrorSink); + } + + virtual void setErrorSink(ErrorSink* pErrorSink) { + mErrorSink = pErrorSink; + if (pCodeBuf) { + pCodeBuf->setErrorSink(mErrorSink); + } + } + + /* Give the code generator some utility types so it can + * use its own types as needed for the results of some + * operations like gcmp. + */ + + void setTypes(Type* pInt) { + mkpInt = pInt; + } + + /* Emit a function prolog. + * pDecl is the function declaration, which gives the arguments. + * Save the old value of the FP. + * Set the new value of the FP. + * Convert from the native platform calling convention to + * our stack-based calling convention. This may require + * pushing arguments from registers to the stack. + * Allocate "N" bytes of stack space. N isn't known yet, so + * just emit the instructions for adjusting the stack, and return + * the address to patch up. The patching will be done in + * functionExit(). + * returns address to patch with local variable size. + */ + virtual int functionEntry(Type* pDecl) = 0; + + /* Emit a function epilog. + * Restore the old SP and FP register values. + * Return to the calling function. + * argCount - the number of arguments to the function. + * localVariableAddress - returned from functionEntry() + * localVariableSize - the size in bytes of the local variables. + */ + virtual void functionExit(Type* pDecl, int localVariableAddress, + int localVariableSize) = 0; + + /* load immediate value to R0 */ + virtual void li(int i) = 0; + + /* Load floating point value from global address. */ + virtual void loadFloat(int address, Type* pType) = 0; + + /* Add the struct offset in bytes to R0, change the type to pType */ + virtual void addStructOffsetR0(int offset, Type* pType) = 0; + + /* Jump to a target, and return the address of the word that + * holds the target data, in case it needs to be fixed up later. + */ + virtual int gjmp(int t) = 0; + + /* Test R0 and jump to a target if the test succeeds. + * l = 0: je, l == 1: jne + * Return the address of the word that holds the targed data, in + * case it needs to be fixed up later. + */ + virtual int gtst(bool l, int t) = 0; + + /* Compare TOS against R0, and store the boolean result in R0. + * Pops TOS. + * op specifies the comparison. + */ + virtual void gcmp(int op) = 0; + + /* Perform the arithmetic op specified by op. TOS is the + * left argument, R0 is the right argument. + * Pops TOS. + */ + virtual void genOp(int op) = 0; + + /* Compare 0 against R0, and store the boolean result in R0. + * op specifies the comparison. + */ + virtual void gUnaryCmp(int op) = 0; + + /* Perform the arithmetic op specified by op. 0 is the + * left argument, R0 is the right argument. + */ + virtual void genUnaryOp(int op) = 0; + + /* Push R0 onto the stack. (Also known as "dup" for duplicate.) + */ + virtual void pushR0() = 0; + + /* Turn R0, TOS into R0 TOS R0 */ + + virtual void over() = 0; + + /* Pop R0 from the stack. (Also known as "drop") + */ + virtual void popR0() = 0; + + /* Store R0 to the address stored in TOS. + * The TOS is popped. + */ + virtual void storeR0ToTOS() = 0; + + /* Load R0 from the address stored in R0. + */ + virtual void loadR0FromR0() = 0; + + /* Load the absolute address of a variable to R0. + * If ea <= LOCAL, then this is a local variable, or an + * argument, addressed relative to FP. + * else it is an absolute global address. + * + * et is ET_RVALUE for things like string constants, ET_LVALUE for + * variables. + */ + virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0; + + /* Load the pc-relative address of a forward-referenced variable to R0. + * Return the address of the 4-byte constant so that it can be filled + * in later. + */ + virtual int leaForward(int ea, Type* pPointerType) = 0; + + /** + * Convert R0 to the given type. + */ + + void convertR0(Type* pType) { + convertR0Imp(pType, false); + } + + void castR0(Type* pType) { + convertR0Imp(pType, true); + } + + virtual void convertR0Imp(Type* pType, bool isCast) = 0; + + /* Emit code to adjust the stack for a function call. Return the + * label for the address of the instruction that adjusts the + * stack size. This will be passed as argument "a" to + * endFunctionCallArguments. + */ + virtual int beginFunctionCallArguments() = 0; + + /* Emit code to store R0 to the stack at byte offset l. + * Returns stack size of object (typically 4 or 8 bytes) + */ + virtual size_t storeR0ToArg(int l, Type* pArgType) = 0; + + /* Patch the function call preamble. + * a is the address returned from beginFunctionCallArguments + * l is the number of bytes the arguments took on the stack. + * Typically you would also emit code to convert the argument + * list into whatever the native function calling convention is. + * On ARM for example you would pop the first 5 arguments into + * R0..R4 + */ + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0; + + /* Emit a call to an unknown function. The argument "symbol" needs to + * be stored in the location where the address should go. It forms + * a chain. The address will be patched later. + * Return the address of the word that has to be patched. + */ + virtual int callForward(int symbol, Type* pFunc) = 0; + + /* Call a function pointer. L is the number of bytes the arguments + * take on the stack. The address of the function is stored at + * location SP + l. + */ + virtual void callIndirect(int l, Type* pFunc) = 0; + + /* Adjust SP after returning from a function call. l is the + * number of bytes of arguments stored on the stack. isIndirect + * is true if this was an indirect call. (In which case the + * address of the function is stored at location SP + l.) + */ + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0; + + /* Generate a symbol at the current PC. t is the head of a + * linked list of addresses to patch. + */ + virtual void gsym(int t) = 0; + + /* Resolve a forward reference function at the current PC. + * t is the head of a + * linked list of addresses to patch. + * (Like gsym, but using absolute address, not PC relative address.) + */ + virtual void resolveForward(int t) = 0; + + /* + * Do any cleanup work required at the end of a compile. + * For example, an instruction cache might need to be + * invalidated. + * Return non-zero if there is an error. + */ + virtual int finishCompile() = 0; + + /** + * Adjust relative branches by this amount. + */ + virtual int jumpOffset() = 0; + + /** + * Memory alignment (in bytes) for this type of data + */ + virtual size_t alignmentOf(Type* type) = 0; + + /** + * Array element alignment (in bytes) for this type of data. + */ + virtual size_t sizeOf(Type* type) = 0; + + virtual Type* getR0Type() { + return mExpressionStack.back().pType; + } + + virtual ExpressionType getR0ExpressionType() { + return mExpressionStack.back().et; + } + + virtual void setR0ExpressionType(ExpressionType et) { + mExpressionStack.back().et = et; + } + + virtual size_t getExpressionStackDepth() { + return mExpressionStack.size(); + } + + virtual void forceR0RVal() { + if (getR0ExpressionType() == ET_LVALUE) { + loadR0FromR0(); + } + } + + protected: + /* + * Output a byte. Handles all values, 0..ff. + */ + void ob(int n) { + pCodeBuf->ob(n); + } + + void o4(int data) { + pCodeBuf->o4(data); + } + + intptr_t getBase() { + return (intptr_t) pCodeBuf->getBase(); + } + + intptr_t getPC() { + return pCodeBuf->getPC(); + } + + intptr_t getSize() { + return pCodeBuf->getSize(); + } + + void flush() { + pCodeBuf->flush(); + } + + void error(const char* fmt,...) { + va_list ap; + va_start(ap, fmt); + mErrorSink->verror(fmt, ap); + va_end(ap); + } + + void assertImpl(bool test, int line) { + if (!test) { + error("code generator assertion failed at line %s:%d.", __FILE__, line); + LOGD("code generator assertion failed at line %s:%d.", __FILE__, line); + * (char*) 0 = 0; + } + } + + void setR0Type(Type* pType) { + assert(pType != NULL); + mExpressionStack.back().pType = pType; + mExpressionStack.back().et = ET_RVALUE; + } + + void setR0Type(Type* pType, ExpressionType et) { + assert(pType != NULL); + mExpressionStack.back().pType = pType; + mExpressionStack.back().et = et; + } + + Type* getTOSType() { + return mExpressionStack[mExpressionStack.size()-2].pType; + } + + void pushType() { + if (mExpressionStack.size()) { + mExpressionStack.push_back(mExpressionStack.back()); + } else { + mExpressionStack.push_back(ExpressionValue()); + } + + } + + void overType() { + size_t size = mExpressionStack.size(); + if (size >= 2) { + mExpressionStack.push_back(mExpressionStack.back()); + mExpressionStack[size-1] = mExpressionStack[size-2]; + mExpressionStack[size-2] = mExpressionStack[size]; + } + } + + void popType() { + mExpressionStack.pop_back(); + } + + bool bitsSame(Type* pA, Type* pB) { + return collapseType(pA->tag) == collapseType(pB->tag); + } + + TypeTag collapseType(TypeTag tag) { + static const TypeTag collapsedTag[] = { + TY_INT, + TY_INT, + TY_INT, + TY_VOID, + TY_FLOAT, + TY_DOUBLE, + TY_INT, + TY_INT, + TY_VOID, + TY_VOID, + TY_VOID + }; + return collapsedTag[tag]; + } + + TypeTag collapseTypeR0() { + return collapseType(getR0Type()->tag); + } + + static bool isFloatType(Type* pType) { + return isFloatTag(pType->tag); + } + + static bool isFloatTag(TypeTag tag) { + return tag == TY_FLOAT || tag == TY_DOUBLE; + } + + static bool isPointerType(Type* pType) { + return isPointerTag(pType->tag); + } + + static bool isPointerTag(TypeTag tag) { + return tag == TY_POINTER || tag == TY_ARRAY; + } + + Type* getPointerArithmeticResultType(Type* a, Type* b) { + TypeTag aTag = a->tag; + TypeTag bTag = b->tag; + if (aTag == TY_POINTER) { + return a; + } + if (bTag == TY_POINTER) { + return b; + } + if (aTag == TY_ARRAY) { + return a->pTail; + } + if (bTag == TY_ARRAY) { + return b->pTail; + } + return NULL; + } + Type* mkpInt; + + private: + Vector mExpressionStack; + ICodeBuf* pCodeBuf; + ErrorSink* mErrorSink; + }; + +#ifdef PROVIDE_ARM_CODEGEN + + static size_t rotateRight(size_t n, size_t rotate) { + return (n >> rotate) | (n << (32 - rotate)); + } + + static size_t rotateLeft(size_t n, size_t rotate) { + return (n << rotate) | (n >> (32 - rotate)); + } + + static bool encode12BitImmediate(size_t immediate, size_t* pResult) { + for(size_t i = 0; i < 16; i++) { + size_t rotate = i * 2; + size_t mask = rotateRight(0xff, rotate); + if ((immediate | mask) == mask) { + size_t bits8 = rotateLeft(immediate, rotate); + // assert(bits8 <= 0xff); + *pResult = (i << 8) | bits8; + return true; + } + } + return false; + } + + static size_t decode12BitImmediate(size_t immediate) { + size_t data = immediate & 0xff; + size_t rotate = 2 * ((immediate >> 8) & 0xf); + return rotateRight(data, rotate); + } + + static bool isPowerOfTwo(size_t n) { + return (n != 0) & ((n & (n-1)) == 0); + } + + static size_t log2(size_t n) { + int result = 0; + while (n >>= 1) { + result++; + } + return result; + } + + class ARMCodeBuf : public ICodeBuf { + ICodeBuf* mpBase; + ErrorSink* mErrorSink; + + class CircularQueue { + static const int SIZE = 16; // Must be power of 2 + static const int MASK = SIZE-1; + unsigned int mBuf[SIZE]; + int mHead; + int mCount; + + public: + CircularQueue() { + mHead = 0; + mCount = 0; + } + + void pushBack(unsigned int data) { + mBuf[(mHead + mCount) & MASK] = data; + mCount += 1; + } + + unsigned int popFront() { + unsigned int result = mBuf[mHead]; + mHead = (mHead + 1) & MASK; + mCount -= 1; + return result; + } + + void popBack(int n) { + mCount -= n; + } + + inline int count() { + return mCount; + } + + bool empty() { + return mCount == 0; + } + + bool full() { + return mCount == SIZE; + } + + // The valid indexes are 1 - count() to 0 + unsigned int operator[](int i) { + return mBuf[(mHead + mCount + i) & MASK]; + } + }; + + CircularQueue mQ; + + void error(const char* fmt,...) { + va_list ap; + va_start(ap, fmt); + mErrorSink->verror(fmt, ap); + va_end(ap); + } + + void flush() { + while (!mQ.empty()) { + mpBase->o4(mQ.popFront()); + } + mpBase->flush(); + } + + public: + ARMCodeBuf(ICodeBuf* pBase) { + mpBase = pBase; + } + + virtual ~ARMCodeBuf() { + delete mpBase; + } + + void init(int size) { + mpBase->init(size); + } + + void setErrorSink(ErrorSink* pErrorSink) { + mErrorSink = pErrorSink; + mpBase->setErrorSink(pErrorSink); + } + + void o4(int n) { + if (mQ.full()) { + mpBase->o4(mQ.popFront()); + } + mQ.pushBack(n); + +#ifndef DISABLE_ARM_PEEPHOLE + // Peephole check + bool didPeep; + do { + static const unsigned int opMask = 0x01e00000; + static const unsigned int immediateMask = 0x00000fff; + static const unsigned int BMask = 0x00400000; + didPeep = false; + if (mQ.count() >= 4) { + + // Operand by a small constant + // push;mov #imm;pop;op ==> op #imm + + if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0} + (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X + mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1} + (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0 + unsigned int movConst = mQ[-3]; + unsigned int op = mQ[-1]; + unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask); + // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined); + if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0 + mQ.popBack(4); + mQ.pushBack(combined); + didPeep = true; + } else { + mQ.popBack(4); + didPeep = true; + } + } + } + + // Load local variable + // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm] + if (mQ.count() >= 2) { + if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm + const unsigned int encodedImmediate = mQ[-2] & immediateMask; + const unsigned int ld = mQ[-1]; + if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0] + unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0] + mQ.popBack(2); + mQ.pushBack(combined); + didPeep = true; + } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000] + unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate); + if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) { + unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0] + mQ.popBack(2); + mQ.pushBack(combined); + didPeep = true; + } + } + } + } + + // Constant array lookup + + if (mQ.count() >= 6 && + mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0} + (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001 + mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1} + (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004 + mQ[-2] == 0xe0000092 && // mul r0, r2, r0 + mQ[-1] == 0xe0810000) { // add r0, r1, r0 + unsigned int mov1 = mQ[-5]; + unsigned int mov2 = mQ[-3]; + unsigned int const1 = decode12BitImmediate(mov1); + unsigned int const2 = decode12BitImmediate(mov2); + unsigned int comboConst = const1 * const2; + size_t immediate = 0; + if (encode12BitImmediate(comboConst, &immediate)) { + mQ.popBack(6); + unsigned int add = immediate | 0xE2800000; // add r0, r0, #n + if (comboConst) { + mQ.pushBack(add); + } + didPeep = true; + } + } + + // Pointer arithmetic with a stride that is a power of two + + if (mQ.count() >= 3 && + (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride + mQ[-2] == 0xe0000092 && // mul r0, r2, r0 + mQ[-1] == 0xe0810000) { // add r0, r1, r0 + int stride = decode12BitImmediate(mQ[-3]); + if (isPowerOfTwo(stride)) { + mQ.popBack(3); + unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride) + mQ.pushBack(add); + didPeep = true; + } + } + + } while (didPeep); +#endif + } + + void ob(int n) { + error("ob() not supported."); + } + + void* getBase() { + flush(); + return mpBase->getBase(); + } + + intptr_t getSize() { + flush(); + return mpBase->getSize(); + } + + intptr_t getPC() { + flush(); + return mpBase->getPC(); + } + }; + + class ARMCodeGenerator : public CodeGenerator { + public: + ARMCodeGenerator() { +#ifdef ARM_USE_VFP + // LOGD("Using ARM VFP hardware floating point."); +#else + // LOGD("Using ARM soft floating point."); +#endif + } + + virtual ~ARMCodeGenerator() {} + + /* returns address to patch with local variable size + */ + virtual int functionEntry(Type* pDecl) { + mStackUse = 0; + // sp -> arg4 arg5 ... + // Push our register-based arguments back on the stack + int regArgCount = calcRegArgCount(pDecl); + if (regArgCount > 0) { + mStackUse += regArgCount * 4; + o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {} + } + // sp -> arg0 arg1 ... + o4(0xE92D4800); // stmfd sp!, {fp, lr} + mStackUse += 2 * 4; + // sp, fp -> oldfp, retadr, arg0 arg1 .... + o4(0xE1A0B00D); // mov fp, sp + LOG_STACK("functionEntry: %d\n", mStackUse); + int pc = getPC(); + o4(0xE24DD000); // sub sp, sp, # + // We don't know how many local variables we are going to use, + // but we will round the allocation up to a multiple of + // STACK_ALIGNMENT, so it won't affect the stack alignment. + return pc; + } + + virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { + // Round local variable size up to a multiple of stack alignment + localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) / + STACK_ALIGNMENT) * STACK_ALIGNMENT; + // Patch local variable allocation code: + if (localVariableSize < 0 || localVariableSize > 255) { + error("localVariables out of range: %d", localVariableSize); + } + *(char*) (localVariableAddress) = localVariableSize; + +#ifdef ARM_USE_VFP + { + Type* pReturnType = pDecl->pHead; + switch(pReturnType->tag) { + case TY_FLOAT: + o4(0xEE170A90); // fmrs r0, s15 + break; + case TY_DOUBLE: + o4(0xEC510B17); // fmrrd r0, r1, d7 + break; + default: + break; + } + } +#endif + + // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ... + o4(0xE1A0E00B); // mov lr, fp + o4(0xE59BB000); // ldr fp, [fp] + o4(0xE28ED004); // add sp, lr, #4 + // sp -> retadr, arg0, ... + o4(0xE8BD4000); // ldmfd sp!, {lr} + // sp -> arg0 .... + + // We store the PC into the lr so we can adjust the sp before + // returning. We need to pull off the registers we pushed + // earlier. We don't need to actually store them anywhere, + // just adjust the stack. + int regArgCount = calcRegArgCount(pDecl); + if (regArgCount) { + o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2 + } + o4(0xE12FFF1E); // bx lr + } + + /* load immediate value */ + virtual void li(int t) { + liReg(t, 0); + setR0Type(mkpInt); + } + + virtual void loadFloat(int address, Type* pType) { + setR0Type(pType); + // Global, absolute address + o4(0xE59F0000); // ldr r0, .L1 + o4(0xEA000000); // b .L99 + o4(address); // .L1: .word ea + // .L99: + + switch (pType->tag) { + case TY_FLOAT: +#ifdef ARM_USE_VFP + o4(0xEDD07A00); // flds s15, [r0] +#else + o4(0xE5900000); // ldr r0, [r0] +#endif + break; + case TY_DOUBLE: +#ifdef ARM_USE_VFP + o4(0xED907B00); // fldd d7, [r0] +#else + o4(0xE1C000D0); // ldrd r0, [r0] +#endif + break; + default: + assert(false); + break; + } + } + + + virtual void addStructOffsetR0(int offset, Type* pType) { + if (offset) { + size_t immediate = 0; + if (encode12BitImmediate(offset, &immediate)) { + o4(0xE2800000 | immediate); // add r0, r0, #offset + } else { + error("structure offset out of range: %d", offset); + } + } + setR0Type(pType, ET_LVALUE); + } + + virtual int gjmp(int t) { + int pc = getPC(); + o4(0xEA000000 | encodeAddress(t)); // b .L33 + return pc; + } + + /* l = 0: je, l == 1: jne */ + virtual int gtst(bool l, int t) { + Type* pR0Type = getR0Type(); + TypeTag tagR0 = pR0Type->tag; + switch(tagR0) { + case TY_FLOAT: +#ifdef ARM_USE_VFP + o4(0xEEF57A40); // fcmpzs s15 + o4(0xEEF1FA10); // fmstat +#else + callRuntime((void*) runtime_is_non_zero_f); + o4(0xE3500000); // cmp r0,#0 +#endif + break; + case TY_DOUBLE: +#ifdef ARM_USE_VFP + o4(0xEEB57B40); // fcmpzd d7 + o4(0xEEF1FA10); // fmstat +#else + callRuntime((void*) runtime_is_non_zero_d); + o4(0xE3500000); // cmp r0,#0 +#endif + break; + default: + o4(0xE3500000); // cmp r0,#0 + break; + } + int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq + int pc = getPC(); + o4(branch | encodeAddress(t)); + return pc; + } + + virtual void gcmp(int op) { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = collapseType(pR0Type->tag); + TypeTag tagTOS = collapseType(pTOSType->tag); + if (tagR0 == TY_INT && tagTOS == TY_INT) { + setupIntPtrArgs(); + o4(0xE1510000); // cmp r1, r1 + switch(op) { + case OP_EQUALS: + o4(0x03A00001); // moveq r0,#1 + o4(0x13A00000); // movne r0,#0 + break; + case OP_NOT_EQUALS: + o4(0x03A00000); // moveq r0,#0 + o4(0x13A00001); // movne r0,#1 + break; + case OP_LESS_EQUAL: + o4(0xD3A00001); // movle r0,#1 + o4(0xC3A00000); // movgt r0,#0 + break; + case OP_GREATER: + o4(0xD3A00000); // movle r0,#0 + o4(0xC3A00001); // movgt r0,#1 + break; + case OP_GREATER_EQUAL: + o4(0xA3A00001); // movge r0,#1 + o4(0xB3A00000); // movlt r0,#0 + break; + case OP_LESS: + o4(0xA3A00000); // movge r0,#0 + o4(0xB3A00001); // movlt r0,#1 + break; + default: + error("Unknown comparison op %d", op); + break; + } + } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) { + setupDoubleArgs(); +#ifdef ARM_USE_VFP + o4(0xEEB46BC7); // fcmped d6, d7 + o4(0xEEF1FA10); // fmstat + switch(op) { + case OP_EQUALS: + o4(0x03A00001); // moveq r0,#1 + o4(0x13A00000); // movne r0,#0 + break; + case OP_NOT_EQUALS: + o4(0x03A00000); // moveq r0,#0 + o4(0x13A00001); // movne r0,#1 + break; + case OP_LESS_EQUAL: + o4(0xD3A00001); // movle r0,#1 + o4(0xC3A00000); // movgt r0,#0 + break; + case OP_GREATER: + o4(0xD3A00000); // movle r0,#0 + o4(0xC3A00001); // movgt r0,#1 + break; + case OP_GREATER_EQUAL: + o4(0xA3A00001); // movge r0,#1 + o4(0xB3A00000); // movlt r0,#0 + break; + case OP_LESS: + o4(0xA3A00000); // movge r0,#0 + o4(0xB3A00001); // movlt r0,#1 + break; + default: + error("Unknown comparison op %d", op); + break; + } +#else + switch(op) { + case OP_EQUALS: + callRuntime((void*) runtime_cmp_eq_dd); + break; + case OP_NOT_EQUALS: + callRuntime((void*) runtime_cmp_ne_dd); + break; + case OP_LESS_EQUAL: + callRuntime((void*) runtime_cmp_le_dd); + break; + case OP_GREATER: + callRuntime((void*) runtime_cmp_gt_dd); + break; + case OP_GREATER_EQUAL: + callRuntime((void*) runtime_cmp_ge_dd); + break; + case OP_LESS: + callRuntime((void*) runtime_cmp_lt_dd); + break; + default: + error("Unknown comparison op %d", op); + break; + } +#endif + } else { + setupFloatArgs(); +#ifdef ARM_USE_VFP + o4(0xEEB47AE7); // fcmpes s14, s15 + o4(0xEEF1FA10); // fmstat + switch(op) { + case OP_EQUALS: + o4(0x03A00001); // moveq r0,#1 + o4(0x13A00000); // movne r0,#0 + break; + case OP_NOT_EQUALS: + o4(0x03A00000); // moveq r0,#0 + o4(0x13A00001); // movne r0,#1 + break; + case OP_LESS_EQUAL: + o4(0xD3A00001); // movle r0,#1 + o4(0xC3A00000); // movgt r0,#0 + break; + case OP_GREATER: + o4(0xD3A00000); // movle r0,#0 + o4(0xC3A00001); // movgt r0,#1 + break; + case OP_GREATER_EQUAL: + o4(0xA3A00001); // movge r0,#1 + o4(0xB3A00000); // movlt r0,#0 + break; + case OP_LESS: + o4(0xA3A00000); // movge r0,#0 + o4(0xB3A00001); // movlt r0,#1 + break; + default: + error("Unknown comparison op %d", op); + break; + } +#else + switch(op) { + case OP_EQUALS: + callRuntime((void*) runtime_cmp_eq_ff); + break; + case OP_NOT_EQUALS: + callRuntime((void*) runtime_cmp_ne_ff); + break; + case OP_LESS_EQUAL: + callRuntime((void*) runtime_cmp_le_ff); + break; + case OP_GREATER: + callRuntime((void*) runtime_cmp_gt_ff); + break; + case OP_GREATER_EQUAL: + callRuntime((void*) runtime_cmp_ge_ff); + break; + case OP_LESS: + callRuntime((void*) runtime_cmp_lt_ff); + break; + default: + error("Unknown comparison op %d", op); + break; + } +#endif + } + setR0Type(mkpInt); + } + + virtual void genOp(int op) { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (!isFloatR0 && !isFloatTOS) { + setupIntPtrArgs(); + bool isPtrR0 = isPointerTag(tagR0); + bool isPtrTOS = isPointerTag(tagTOS); + if (isPtrR0 || isPtrTOS) { + if (isPtrR0 && isPtrTOS) { + if (op != OP_MINUS) { + error("Unsupported pointer-pointer operation %d.", op); + } + if (! typeEqual(pR0Type, pTOSType)) { + error("Incompatible pointer types for subtraction."); + } + o4(0xE0410000); // sub r0,r1,r0 + setR0Type(mkpInt); + int size = sizeOf(pR0Type->pHead); + if (size != 1) { + pushR0(); + li(size); + // TODO: Optimize for power-of-two. + genOp(OP_DIV); + } + } else { + if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) { + error("Unsupported pointer-scalar operation %d", op); + } + Type* pPtrType = getPointerArithmeticResultType( + pR0Type, pTOSType); + int size = sizeOf(pPtrType->pHead); + if (size != 1) { + // TODO: Optimize for power-of-two. + liReg(size, 2); + if (isPtrR0) { + o4(0x0E0010192); // mul r1,r2,r1 + } else { + o4(0x0E0000092); // mul r0,r2,r0 + } + } + switch(op) { + case OP_PLUS: + o4(0xE0810000); // add r0,r1,r0 + break; + case OP_MINUS: + o4(0xE0410000); // sub r0,r1,r0 + break; + } + setR0Type(pPtrType); + } + } else { + switch(op) { + case OP_MUL: + o4(0x0E0000091); // mul r0,r1,r0 + break; + case OP_DIV: + callRuntime((void*) runtime_DIV); + break; + case OP_MOD: + callRuntime((void*) runtime_MOD); + break; + case OP_PLUS: + o4(0xE0810000); // add r0,r1,r0 + break; + case OP_MINUS: + o4(0xE0410000); // sub r0,r1,r0 + break; + case OP_SHIFT_LEFT: + o4(0xE1A00011); // lsl r0,r1,r0 + break; + case OP_SHIFT_RIGHT: + o4(0xE1A00051); // asr r0,r1,r0 + break; + case OP_BIT_AND: + o4(0xE0010000); // and r0,r1,r0 + break; + case OP_BIT_XOR: + o4(0xE0210000); // eor r0,r1,r0 + break; + case OP_BIT_OR: + o4(0xE1810000); // orr r0,r1,r0 + break; + case OP_BIT_NOT: + o4(0xE1E00000); // mvn r0, r0 + break; + default: + error("Unimplemented op %d\n", op); + break; + } + } + } else { + Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType; + if (pResultType->tag == TY_DOUBLE) { + setupDoubleArgs(); + + switch(op) { + case OP_MUL: +#ifdef ARM_USE_VFP + o4(0xEE267B07); // fmuld d7, d6, d7 +#else + callRuntime((void*) runtime_op_mul_dd); +#endif + break; + case OP_DIV: +#ifdef ARM_USE_VFP + o4(0xEE867B07); // fdivd d7, d6, d7 +#else + callRuntime((void*) runtime_op_div_dd); +#endif + break; + case OP_PLUS: +#ifdef ARM_USE_VFP + o4(0xEE367B07); // faddd d7, d6, d7 +#else + callRuntime((void*) runtime_op_add_dd); +#endif + break; + case OP_MINUS: +#ifdef ARM_USE_VFP + o4(0xEE367B47); // fsubd d7, d6, d7 +#else + callRuntime((void*) runtime_op_sub_dd); +#endif + break; + default: + error("Unsupported binary floating operation %d\n", op); + break; + } + } else { + setupFloatArgs(); + switch(op) { + case OP_MUL: +#ifdef ARM_USE_VFP + o4(0xEE677A27); // fmuls s15, s14, s15 +#else + callRuntime((void*) runtime_op_mul_ff); +#endif + break; + case OP_DIV: +#ifdef ARM_USE_VFP + o4(0xEEC77A27); // fdivs s15, s14, s15 +#else + callRuntime((void*) runtime_op_div_ff); +#endif + break; + case OP_PLUS: +#ifdef ARM_USE_VFP + o4(0xEE777A27); // fadds s15, s14, s15 +#else + callRuntime((void*) runtime_op_add_ff); +#endif + break; + case OP_MINUS: +#ifdef ARM_USE_VFP + o4(0xEE777A67); // fsubs s15, s14, s15 +#else + callRuntime((void*) runtime_op_sub_ff); +#endif + break; + default: + error("Unsupported binary floating operation %d\n", op); + break; + } + } + setR0Type(pResultType); + } + } + + virtual void gUnaryCmp(int op) { + if (op != OP_LOGICAL_NOT) { + error("Unknown unary cmp %d", op); + } else { + Type* pR0Type = getR0Type(); + TypeTag tag = collapseType(pR0Type->tag); + switch(tag) { + case TY_INT: + o4(0xE3A01000); // mov r1, #0 + o4(0xE1510000); // cmp r1, r0 + o4(0x03A00001); // moveq r0,#1 + o4(0x13A00000); // movne r0,#0 + break; + case TY_FLOAT: +#ifdef ARM_USE_VFP + o4(0xEEF57A40); // fcmpzs s15 + o4(0xEEF1FA10); // fmstat + o4(0x03A00001); // moveq r0,#1 + o4(0x13A00000); // movne r0,#0 +#else + callRuntime((void*) runtime_is_zero_f); +#endif + break; + case TY_DOUBLE: +#ifdef ARM_USE_VFP + o4(0xEEB57B40); // fcmpzd d7 + o4(0xEEF1FA10); // fmstat + o4(0x03A00001); // moveq r0,#1 + o4(0x13A00000); // movne r0,#0 +#else + callRuntime((void*) runtime_is_zero_d); +#endif + break; + default: + error("gUnaryCmp unsupported type"); + break; + } + } + setR0Type(mkpInt); + } + + virtual void genUnaryOp(int op) { + Type* pR0Type = getR0Type(); + TypeTag tag = collapseType(pR0Type->tag); + switch(tag) { + case TY_INT: + switch(op) { + case OP_MINUS: + o4(0xE3A01000); // mov r1, #0 + o4(0xE0410000); // sub r0,r1,r0 + break; + case OP_BIT_NOT: + o4(0xE1E00000); // mvn r0, r0 + break; + default: + error("Unknown unary op %d\n", op); + break; + } + break; + case TY_FLOAT: + case TY_DOUBLE: + switch (op) { + case OP_MINUS: + if (tag == TY_FLOAT) { +#ifdef ARM_USE_VFP + o4(0xEEF17A67); // fnegs s15, s15 +#else + callRuntime((void*) runtime_op_neg_f); +#endif + } else { +#ifdef ARM_USE_VFP + o4(0xEEB17B47); // fnegd d7, d7 +#else + callRuntime((void*) runtime_op_neg_d); +#endif + } + break; + case OP_BIT_NOT: + error("Can't apply '~' operator to a float or double."); + break; + default: + error("Unknown unary op %d\n", op); + break; + } + break; + default: + error("genUnaryOp unsupported type"); + break; + } + } + + virtual void pushR0() { + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); + +#ifdef ARM_USE_VFP + switch (r0ct ) { + case TY_FLOAT: + o4(0xED6D7A01); // fstmfds sp!,{s15} + mStackUse += 4; + break; + case TY_DOUBLE: + o4(0xED2D7B02); // fstmfdd sp!,{d7} + mStackUse += 8; + break; + default: + o4(0xE92D0001); // stmfd sp!,{r0} + mStackUse += 4; + } +#else + + if (r0ct != TY_DOUBLE) { + o4(0xE92D0001); // stmfd sp!,{r0} + mStackUse += 4; + } else { + o4(0xE92D0003); // stmfd sp!,{r0,r1} + mStackUse += 8; + } +#endif + pushType(); + LOG_STACK("pushR0: %d\n", mStackUse); + } + + virtual void over() { + // We know it's only used for int-ptr ops (++/--) + + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); + + Type* pTOSType = getTOSType(); + TypeTag tosct = collapseType(pTOSType->tag); + + assert (r0ct == TY_INT && tosct == TY_INT); + + o4(0xE8BD0002); // ldmfd sp!,{r1} + o4(0xE92D0001); // stmfd sp!,{r0} + o4(0xE92D0002); // stmfd sp!,{r1} + overType(); + mStackUse += 4; + } + + virtual void popR0() { + Type* pTOSType = getTOSType(); + TypeTag tosct = collapseType(pTOSType->tag); +#ifdef ARM_USE_VFP + if (tosct == TY_FLOAT || tosct == TY_DOUBLE) { + error("Unsupported popR0 float/double"); + } +#endif + switch (tosct){ + case TY_INT: + case TY_FLOAT: + o4(0xE8BD0001); // ldmfd sp!,{r0} + mStackUse -= 4; + break; + case TY_DOUBLE: + o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0 + mStackUse -= 8; + break; + default: + error("Can't pop this type."); + break; + } + popType(); + LOG_STACK("popR0: %d\n", mStackUse); + } + + virtual void storeR0ToTOS() { + Type* pPointerType = getTOSType(); + assert(pPointerType->tag == TY_POINTER); + Type* pDestType = pPointerType->pHead; + convertR0(pDestType); + o4(0xE8BD0004); // ldmfd sp!,{r2} + popType(); + mStackUse -= 4; + switch (pDestType->tag) { + case TY_POINTER: + case TY_INT: + o4(0xE5820000); // str r0, [r2] + break; + case TY_FLOAT: +#ifdef ARM_USE_VFP + o4(0xEDC27A00); // fsts s15, [r2, #0] +#else + o4(0xE5820000); // str r0, [r2] +#endif + break; + case TY_SHORT: + o4(0xE1C200B0); // strh r0, [r2] + break; + case TY_CHAR: + o4(0xE5C20000); // strb r0, [r2] + break; + case TY_DOUBLE: +#ifdef ARM_USE_VFP + o4(0xED827B00); // fstd d7, [r2, #0] +#else + o4(0xE1C200F0); // strd r0, [r2] +#endif + break; + case TY_STRUCT: + { + int size = sizeOf(pDestType); + if (size > 0) { + liReg(size, 1); + callRuntime((void*) runtime_structCopy); + } + } + break; + default: + error("storeR0ToTOS: unimplemented type %d", + pDestType->tag); + break; + } + setR0Type(pDestType); + } + + virtual void loadR0FromR0() { + Type* pPointerType = getR0Type(); + assert(pPointerType->tag == TY_POINTER); + Type* pNewType = pPointerType->pHead; + TypeTag tag = pNewType->tag; + switch (tag) { + case TY_POINTER: + case TY_INT: + o4(0xE5900000); // ldr r0, [r0] + break; + case TY_FLOAT: +#ifdef ARM_USE_VFP + o4(0xEDD07A00); // flds s15, [r0, #0] +#else + o4(0xE5900000); // ldr r0, [r0] +#endif + break; + case TY_SHORT: + o4(0xE1D000F0); // ldrsh r0, [r0] + break; + case TY_CHAR: + o4(0xE5D00000); // ldrb r0, [r0] + break; + case TY_DOUBLE: +#ifdef ARM_USE_VFP + o4(0xED907B00); // fldd d7, [r0, #0] +#else + o4(0xE1C000D0); // ldrd r0, [r0] +#endif + break; + case TY_ARRAY: + pNewType = pNewType->pTail; + break; + case TY_STRUCT: + break; + default: + error("loadR0FromR0: unimplemented type %d", tag); + break; + } + setR0Type(pNewType); + } + + virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { + if (ea > -LOCAL && ea < LOCAL) { + // Local, fp relative + + size_t immediate = 0; + bool inRange = false; + if (ea < 0) { + inRange = encode12BitImmediate(-ea, &immediate); + o4(0xE24B0000 | immediate); // sub r0, fp, #ea + } else { + inRange = encode12BitImmediate(ea, &immediate); + o4(0xE28B0000 | immediate); // add r0, fp, #ea + } + if (! inRange) { + error("Offset out of range: %08x", ea); + } + } else { + // Global, absolute. + o4(0xE59F0000); // ldr r0, .L1 + o4(0xEA000000); // b .L99 + o4(ea); // .L1: .word 0 + // .L99: + } + setR0Type(pPointerType, et); + } + + virtual int leaForward(int ea, Type* pPointerType) { + setR0Type(pPointerType); + int result = ea; + int pc = getPC(); + int offset = 0; + if (ea) { + offset = (pc - ea - 8) >> 2; + if ((offset & 0xffff) != offset) { + error("function forward reference out of bounds"); + } + } else { + offset = 0; + } + o4(0xE59F0000 | offset); // ldr r0, .L1 + + if (ea == 0) { + o4(0xEA000000); // b .L99 + result = getPC(); + o4(ea); // .L1: .word 0 + // .L99: + } + return result; + } + + virtual void convertR0Imp(Type* pType, bool isCast){ + Type* pR0Type = getR0Type(); + if (isPointerType(pType) && isPointerType(pR0Type)) { + Type* pA = pR0Type; + Type* pB = pType; + // Array decays to pointer + if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) { + pA = pA->pTail; + } + if (! (typeEqual(pA, pB) + || pB->pHead->tag == TY_VOID + || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast) + )) { + error("Incompatible pointer or array types"); + } + } else if (bitsSame(pType, pR0Type)) { + // do nothing special + } else { + TypeTag r0Tag = collapseType(pR0Type->tag); + TypeTag destTag = collapseType(pType->tag); + if (r0Tag == TY_INT) { + if (destTag == TY_FLOAT) { +#ifdef ARM_USE_VFP + o4(0xEE070A90); // fmsr s15, r0 + o4(0xEEF87AE7); // fsitos s15, s15 + +#else + callRuntime((void*) runtime_int_to_float); +#endif + } else { + assert(destTag == TY_DOUBLE); +#ifdef ARM_USE_VFP + o4(0xEE070A90); // fmsr s15, r0 + o4(0xEEB87BE7); // fsitod d7, s15 + +#else + callRuntime((void*) runtime_int_to_double); +#endif + } + } else if (r0Tag == TY_FLOAT) { + if (destTag == TY_INT) { +#ifdef ARM_USE_VFP + o4(0xEEFD7AE7); // ftosizs s15, s15 + o4(0xEE170A90); // fmrs r0, s15 +#else + callRuntime((void*) runtime_float_to_int); +#endif + } else { + assert(destTag == TY_DOUBLE); +#ifdef ARM_USE_VFP + o4(0xEEB77AE7); // fcvtds d7, s15 +#else + callRuntime((void*) runtime_float_to_double); +#endif + } + } else { + if (r0Tag == TY_DOUBLE) { + if (destTag == TY_INT) { +#ifdef ARM_USE_VFP + o4(0xEEFD7BC7); // ftosizd s15, d7 + o4(0xEE170A90); // fmrs r0, s15 +#else + callRuntime((void*) runtime_double_to_int); +#endif + } else { + if(destTag == TY_FLOAT) { +#ifdef ARM_USE_VFP + o4(0xEEF77BC7); // fcvtsd s15, d7 +#else + callRuntime((void*) runtime_double_to_float); +#endif + } else { + incompatibleTypes(pR0Type, pType); + } + } + } else { + incompatibleTypes(pR0Type, pType); + } + } + } + setR0Type(pType); + } + + virtual int beginFunctionCallArguments() { + int pc = getPC(); + o4(0xE24DDF00); // Placeholder sub sp, sp, #0 + return pc; + } + + virtual size_t storeR0ToArg(int l, Type* pArgType) { + convertR0(pArgType); + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); +#ifdef ARM_USE_VFP + switch(r0ct) { + case TY_INT: + if (l < 0 || l > 4096-4) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xE58D0000 | l); // str r0, [sp, #l] + return 4; + case TY_FLOAT: + if (l < 0 || l > 1020 || (l & 3)) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l] + return 4; + case TY_DOUBLE: { + // Align to 8 byte boundary + int l2 = (l + 7) & ~7; + if (l2 < 0 || l2 > 1020 || (l2 & 3)) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2] + return (l2 - l) + 8; + } + default: + assert(false); + return 0; + } +#else + switch(r0ct) { + case TY_INT: + case TY_FLOAT: + if (l < 0 || l > 4096-4) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xE58D0000 + l); // str r0, [sp, #l] + return 4; + case TY_DOUBLE: { + // Align to 8 byte boundary + int l2 = (l + 7) & ~7; + if (l2 < 0 || l2 > 4096-8) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xE58D0000 + l2); // str r0, [sp, #l] + o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4] + return (l2 - l) + 8; + } + default: + assert(false); + return 0; + } +#endif + } + + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { + int argumentStackUse = l; + // Have to calculate register arg count from actual stack size, + // in order to properly handle ... functions. + int regArgCount = l >> 2; + if (regArgCount > 4) { + regArgCount = 4; + } + if (regArgCount > 0) { + argumentStackUse -= regArgCount * 4; + o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{} + } + mStackUse += argumentStackUse; + + // Align stack. + int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT) + * STACK_ALIGNMENT); + mStackAlignmentAdjustment = 0; + if (missalignment > 0) { + mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment; + } + l += mStackAlignmentAdjustment; + + if (l < 0 || l > 0x3FC) { + error("L out of range for stack adjustment: 0x%08x", l); + } + flush(); + * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2 + mStackUse += mStackAlignmentAdjustment; + LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n", + mStackUse, mStackAlignmentAdjustment); + } + + virtual int callForward(int symbol, Type* pFunc) { + setR0Type(pFunc->pHead); + // Forward calls are always short (local) + int pc = getPC(); + o4(0xEB000000 | encodeAddress(symbol)); + return pc; + } + + virtual void callIndirect(int l, Type* pFunc) { + assert(pFunc->tag == TY_FUNC); + popType(); // Get rid of indirect fn pointer type + int argCount = l >> 2; + int poppedArgs = argCount > 4 ? 4 : argCount; + int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment; + if (adjustedL < 0 || adjustedL > 4096-4) { + error("l out of range for stack offset: 0x%08x", l); + } + o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL] + o4(0xE12FFF3C); // blx r12 + Type* pReturnType = pFunc->pHead; + setR0Type(pReturnType); +#ifdef ARM_USE_VFP + switch(pReturnType->tag) { + case TY_FLOAT: + o4(0xEE070A90); // fmsr s15, r0 + break; + case TY_DOUBLE: + o4(0xEC410B17); // fmdrr d7, r0, r1 + break; + default: + break; + } +#endif + } + + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { + int argCount = l >> 2; + // Have to calculate register arg count from actual stack size, + // in order to properly handle ... functions. + int regArgCount = l >> 2; + if (regArgCount > 4) { + regArgCount = 4; + } + int stackArgs = argCount - regArgCount; + int stackUse = stackArgs + (isIndirect ? 1 : 0) + + (mStackAlignmentAdjustment >> 2); + if (stackUse) { + if (stackUse < 0 || stackUse > 255) { + error("L out of range for stack adjustment: 0x%08x", l); + } + o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2 + mStackUse -= stackUse * 4; + LOG_STACK("adjustStackAfterCall: %d\n", mStackUse); + } + } + + virtual int jumpOffset() { + return 8; + } + + /* output a symbol and patch all calls to it */ + virtual void gsym(int t) { + int n; + int base = getBase(); + int pc = getPC(); + while (t) { + int data = * (int*) t; + int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2); + if (decodedOffset == 0) { + n = 0; + } else { + n = base + decodedOffset; /* next value */ + } + *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK) + | encodeRelAddress(pc - t - 8); + t = n; + } + } + + /* output a symbol and patch all calls to it */ + virtual void resolveForward(int t) { + if (t) { + int pc = getPC(); + *(int *) t = pc; + } + } + + virtual int finishCompile() { +#if defined(__arm__) + const long base = long(getBase()); + const long curr = long(getPC()); + int err = cacheflush(base, curr, 0); + return err; +#else + return 0; +#endif + } + + /** + * alignment (in bytes) for this type of data + */ + virtual size_t alignmentOf(Type* pType){ + switch(pType->tag) { + case TY_CHAR: + return 1; + case TY_SHORT: + return 2; + case TY_DOUBLE: + return 8; + case TY_ARRAY: + return alignmentOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->alignment & 0x7fffffff; + case TY_FUNC: + error("alignment of func not supported"); + return 1; + default: + return 4; + } + } + + /** + * Array element alignment (in bytes) for this type of data. + */ + virtual size_t sizeOf(Type* pType){ + switch(pType->tag) { + case TY_INT: + return 4; + case TY_SHORT: + return 2; + case TY_CHAR: + return 1; + case TY_FLOAT: + return 4; + case TY_DOUBLE: + return 8; + case TY_POINTER: + return 4; + case TY_ARRAY: + return pType->length * sizeOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->length; + default: + error("Unsupported type %d", pType->tag); + return 0; + } + } + + private: + + static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff; + + /** Encode a relative address that might also be + * a label. + */ + int encodeAddress(int value) { + int base = getBase(); + if (value >= base && value <= getPC() ) { + // This is a label, encode it relative to the base. + value = value - base; + } + return encodeRelAddress(value); + } + + int encodeRelAddress(int value) { + return BRANCH_REL_ADDRESS_MASK & (value >> 2); + } + + int calcRegArgCount(Type* pDecl) { + int reg = 0; + Type* pArgs = pDecl->pTail; + while (pArgs && reg < 4) { + Type* pArg = pArgs->pHead; + if ( pArg->tag == TY_DOUBLE) { + int evenReg = (reg + 1) & ~1; + if (evenReg >= 4) { + break; + } + reg = evenReg + 2; + } else { + reg++; + } + pArgs = pArgs->pTail; + } + return reg; + } + + void setupIntPtrArgs() { + o4(0xE8BD0002); // ldmfd sp!,{r1} + mStackUse -= 4; + popType(); + } + + /* Pop TOS to R1 (use s14 if VFP) + * Make sure both R0 and TOS are floats. (Could be ints) + * We know that at least one of R0 and TOS is already a float + */ + void setupFloatArgs() { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = collapseType(pR0Type->tag); + TypeTag tagTOS = collapseType(pTOSType->tag); + if (tagR0 != TY_FLOAT) { + assert(tagR0 == TY_INT); +#ifdef ARM_USE_VFP + o4(0xEE070A90); // fmsr s15, r0 + o4(0xEEF87AE7); // fsitos s15, s15 +#else + callRuntime((void*) runtime_int_to_float); +#endif + } + if (tagTOS != TY_FLOAT) { + assert(tagTOS == TY_INT); + assert(tagR0 == TY_FLOAT); +#ifdef ARM_USE_VFP + o4(0xECBD7A01); // fldmfds sp!, {s14} + o4(0xEEB87AC7); // fsitos s14, s14 +#else + o4(0xE92D0001); // stmfd sp!,{r0} // push R0 + o4(0xE59D0004); // ldr r0, [sp, #4] + callRuntime((void*) runtime_int_to_float); + o4(0xE1A01000); // mov r1, r0 + o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0 + o4(0xE28DD004); // add sp, sp, #4 // Pop sp +#endif + } else { + // Pop TOS +#ifdef ARM_USE_VFP + o4(0xECBD7A01); // fldmfds sp!, {s14} + +#else + o4(0xE8BD0002); // ldmfd sp!,{r1} +#endif + } + mStackUse -= 4; + popType(); + } + + /* Pop TOS into R2..R3 (use D6 if VFP) + * Make sure both R0 and TOS are doubles. Could be floats or ints. + * We know that at least one of R0 and TOS are already a double. + */ + + void setupDoubleArgs() { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = collapseType(pR0Type->tag); + TypeTag tagTOS = collapseType(pTOSType->tag); + if (tagR0 != TY_DOUBLE) { + if (tagR0 == TY_INT) { +#ifdef ARM_USE_VFP + o4(0xEE070A90); // fmsr s15, r0 + o4(0xEEB87BE7); // fsitod d7, s15 + +#else + callRuntime((void*) runtime_int_to_double); +#endif + } else { + assert(tagR0 == TY_FLOAT); +#ifdef ARM_USE_VFP + o4(0xEEB77AE7); // fcvtds d7, s15 +#else + callRuntime((void*) runtime_float_to_double); +#endif + } + } + if (tagTOS != TY_DOUBLE) { +#ifdef ARM_USE_VFP + if (tagTOS == TY_INT) { + o4(0xECFD6A01); // fldmfds sp!,{s13} + o4(0xEEB86BE6); // fsitod d6, s13 + } else { + assert(tagTOS == TY_FLOAT); + o4(0xECFD6A01); // fldmfds sp!,{s13} + o4(0xEEB76AE6); // fcvtds d6, s13 + } +#else + o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1 + o4(0xE59D0008); // ldr r0, [sp, #8] + if (tagTOS == TY_INT) { + callRuntime((void*) runtime_int_to_double); + } else { + assert(tagTOS == TY_FLOAT); + callRuntime((void*) runtime_float_to_double); + } + o4(0xE1A02000); // mov r2, r0 + o4(0xE1A03001); // mov r3, r1 + o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0 + o4(0xE28DD004); // add sp, sp, #4 // Pop sp +#endif + mStackUse -= 4; + } else { +#ifdef ARM_USE_VFP + o4(0xECBD6B02); // fldmfdd sp!, {d6} +#else + o4(0xE8BD000C); // ldmfd sp!,{r2,r3} +#endif + mStackUse -= 8; + } + popType(); + } + + void liReg(int t, int reg) { + assert(reg >= 0 && reg < 16); + int rN = (reg & 0xf) << 12; + size_t encodedImmediate; + if (encode12BitImmediate(t, &encodedImmediate)) { + o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0 + } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) { + // mvn means move constant ^ ~0 + o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0 + } else { + o4(0xE51F0000 | rN); // ldr rN, .L3 + o4(0xEA000000); // b .L99 + o4(t); // .L3: .word 0 + // .L99: + } + } + + void incompatibleTypes(Type* pR0Type, Type* pType) { + error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag); + } + + void callRuntime(void* fn) { + o4(0xE59FC000); // ldr r12, .L1 + o4(0xEA000000); // b .L99 + o4((int) fn); //.L1: .word fn + o4(0xE12FFF3C); //.L99: blx r12 + } + + // Integer math: + + static int runtime_DIV(int b, int a) { + return a / b; + } + + static int runtime_MOD(int b, int a) { + return a % b; + } + + static void runtime_structCopy(void* src, size_t size, void* dest) { + memcpy(dest, src, size); + } + +#ifndef ARM_USE_VFP + + // Comparison to zero + + static int runtime_is_non_zero_f(float a) { + return a != 0; + } + + static int runtime_is_non_zero_d(double a) { + return a != 0; + } + + // Comparison to zero + + static int runtime_is_zero_f(float a) { + return a == 0; + } + + static int runtime_is_zero_d(double a) { + return a == 0; + } + + // Type conversion + + static int runtime_float_to_int(float a) { + return (int) a; + } + + static double runtime_float_to_double(float a) { + return (double) a; + } + + static int runtime_double_to_int(double a) { + return (int) a; + } + + static float runtime_double_to_float(double a) { + return (float) a; + } + + static float runtime_int_to_float(int a) { + return (float) a; + } + + static double runtime_int_to_double(int a) { + return (double) a; + } + + // Comparisons float + + static int runtime_cmp_eq_ff(float b, float a) { + return a == b; + } + + static int runtime_cmp_ne_ff(float b, float a) { + return a != b; + } + + static int runtime_cmp_lt_ff(float b, float a) { + return a < b; + } + + static int runtime_cmp_le_ff(float b, float a) { + return a <= b; + } + + static int runtime_cmp_ge_ff(float b, float a) { + return a >= b; + } + + static int runtime_cmp_gt_ff(float b, float a) { + return a > b; + } + + // Comparisons double + + static int runtime_cmp_eq_dd(double b, double a) { + return a == b; + } + + static int runtime_cmp_ne_dd(double b, double a) { + return a != b; + } + + static int runtime_cmp_lt_dd(double b, double a) { + return a < b; + } + + static int runtime_cmp_le_dd(double b, double a) { + return a <= b; + } + + static int runtime_cmp_ge_dd(double b, double a) { + return a >= b; + } + + static int runtime_cmp_gt_dd(double b, double a) { + return a > b; + } + + // Math float + + static float runtime_op_add_ff(float b, float a) { + return a + b; + } + + static float runtime_op_sub_ff(float b, float a) { + return a - b; + } + + static float runtime_op_mul_ff(float b, float a) { + return a * b; + } + + static float runtime_op_div_ff(float b, float a) { + return a / b; + } + + static float runtime_op_neg_f(float a) { + return -a; + } + + // Math double + + static double runtime_op_add_dd(double b, double a) { + return a + b; + } + + static double runtime_op_sub_dd(double b, double a) { + return a - b; + } + + static double runtime_op_mul_dd(double b, double a) { + return a * b; + } + + static double runtime_op_div_dd(double b, double a) { + return a / b; + } + + static double runtime_op_neg_d(double a) { + return -a; + } + +#endif + + static const int STACK_ALIGNMENT = 8; + int mStackUse; + // This variable holds the amount we adjusted the stack in the most + // recent endFunctionCallArguments call. It's examined by the + // following adjustStackAfterCall call. + int mStackAlignmentAdjustment; + }; + +#endif // PROVIDE_ARM_CODEGEN + +#ifdef PROVIDE_X86_CODEGEN + + class X86CodeGenerator : public CodeGenerator { + public: + X86CodeGenerator() {} + virtual ~X86CodeGenerator() {} + + /* returns address to patch with local variable size + */ + virtual int functionEntry(Type* pDecl) { + o(0xe58955); /* push %ebp, mov %esp, %ebp */ + return oad(0xec81, 0); /* sub $xxx, %esp */ + } + + virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { + o(0xc3c9); /* leave, ret */ + *(int *) localVariableAddress = localVariableSize; /* save local variables */ + } + + /* load immediate value */ + virtual void li(int i) { + oad(0xb8, i); /* mov $xx, %eax */ + setR0Type(mkpInt); + } + + virtual void loadFloat(int address, Type* pType) { + setR0Type(pType); + switch (pType->tag) { + case TY_FLOAT: + oad(0x05D9, address); // flds + break; + case TY_DOUBLE: + oad(0x05DD, address); // fldl + break; + default: + assert(false); + break; + } + } + + virtual void addStructOffsetR0(int offset, Type* pType) { + if (offset) { + oad(0x05, offset); // addl offset, %eax + } + setR0Type(pType, ET_LVALUE); + } + + virtual int gjmp(int t) { + return psym(0xe9, t); + } + + /* l = 0: je, l == 1: jne */ + virtual int gtst(bool l, int t) { + Type* pR0Type = getR0Type(); + TypeTag tagR0 = pR0Type->tag; + bool isFloatR0 = isFloatTag(tagR0); + if (isFloatR0) { + o(0xeed9); // fldz + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + } else { + o(0xc085); // test %eax, %eax + } + // Use two output statements to generate one instruction. + o(0x0f); // je/jne xxx + return psym(0x84 + l, t); + } + + virtual void gcmp(int op) { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (!isFloatR0 && !isFloatTOS) { + int t = decodeOp(op); + o(0x59); /* pop %ecx */ + o(0xc139); /* cmp %eax,%ecx */ + li(0); + o(0x0f); /* setxx %al */ + o(t + 0x90); + o(0xc0); + popType(); + } else { + setupFloatOperands(); + switch (op) { + case OP_EQUALS: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0940f); // sete %al + o(0xc29b0f); // setnp %dl + o(0xd021); // andl %edx, %eax + break; + case OP_NOT_EQUALS: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0950f); // setne %al + o(0xc29a0f); // setp %dl + o(0xd009); // orl %edx, %eax + break; + case OP_GREATER_EQUAL: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x05c4f6); // testb $5, %ah + o(0xc0940f); // sete %al + break; + case OP_LESS: + o(0xc9d9); // fxch %st(1) + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0970f); // seta %al + break; + case OP_LESS_EQUAL: + o(0xc9d9); // fxch %st(1) + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0930f); // setea %al + break; + case OP_GREATER: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x45c4f6); // testb $69, %ah + o(0xc0940f); // sete %al + break; + default: + error("Unknown comparison op"); + } + o(0xc0b60f); // movzbl %al, %eax + } + setR0Type(mkpInt); + } + + virtual void genOp(int op) { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (!isFloatR0 && !isFloatTOS) { + bool isPtrR0 = isPointerTag(tagR0); + bool isPtrTOS = isPointerTag(tagTOS); + if (isPtrR0 || isPtrTOS) { + if (isPtrR0 && isPtrTOS) { + if (op != OP_MINUS) { + error("Unsupported pointer-pointer operation %d.", op); + } + if (! typeEqual(pR0Type, pTOSType)) { + error("Incompatible pointer types for subtraction."); + } + o(0x59); /* pop %ecx */ + o(decodeOp(op)); + popType(); + setR0Type(mkpInt); + int size = sizeOf(pR0Type->pHead); + if (size != 1) { + pushR0(); + li(size); + // TODO: Optimize for power-of-two. + genOp(OP_DIV); + } + } else { + if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) { + error("Unsupported pointer-scalar operation %d", op); + } + Type* pPtrType = getPointerArithmeticResultType( + pR0Type, pTOSType); + o(0x59); /* pop %ecx */ + int size = sizeOf(pPtrType->pHead); + if (size != 1) { + // TODO: Optimize for power-of-two. + if (isPtrR0) { + oad(0xC969, size); // imull $size, %ecx + } else { + oad(0xC069, size); // mul $size, %eax + } + } + o(decodeOp(op)); + popType(); + setR0Type(pPtrType); + } + } else { + o(0x59); /* pop %ecx */ + o(decodeOp(op)); + if (op == OP_MOD) + o(0x92); /* xchg %edx, %eax */ + popType(); + } + } else { + Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType; + setupFloatOperands(); + // Both float. x87 R0 == left hand, x87 R1 == right hand + switch (op) { + case OP_MUL: + o(0xc9de); // fmulp + break; + case OP_DIV: + o(0xf1de); // fdivp + break; + case OP_PLUS: + o(0xc1de); // faddp + break; + case OP_MINUS: + o(0xe1de); // fsubp + break; + default: + error("Unsupported binary floating operation."); + break; + } + setR0Type(pResultType); + } + } + + virtual void gUnaryCmp(int op) { + if (op != OP_LOGICAL_NOT) { + error("Unknown unary cmp %d", op); + } else { + Type* pR0Type = getR0Type(); + TypeTag tag = collapseType(pR0Type->tag); + switch(tag) { + case TY_INT: { + oad(0xb9, 0); /* movl $0, %ecx */ + int t = decodeOp(op); + o(0xc139); /* cmp %eax,%ecx */ + li(0); + o(0x0f); /* setxx %al */ + o(t + 0x90); + o(0xc0); + } + break; + case TY_FLOAT: + case TY_DOUBLE: + o(0xeed9); // fldz + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0950f); // setne %al + o(0xc29a0f); // setp %dl + o(0xd009); // orl %edx, %eax + o(0xc0b60f); // movzbl %al, %eax + o(0x01f083); // xorl $1, %eax + break; + default: + error("gUnaryCmp unsupported type"); + break; + } + } + setR0Type(mkpInt); + } + + virtual void genUnaryOp(int op) { + Type* pR0Type = getR0Type(); + TypeTag tag = collapseType(pR0Type->tag); + switch(tag) { + case TY_INT: + oad(0xb9, 0); /* movl $0, %ecx */ + o(decodeOp(op)); + break; + case TY_FLOAT: + case TY_DOUBLE: + switch (op) { + case OP_MINUS: + o(0xe0d9); // fchs + break; + case OP_BIT_NOT: + error("Can't apply '~' operator to a float or double."); + break; + default: + error("Unknown unary op %d\n", op); + break; + } + break; + default: + error("genUnaryOp unsupported type"); + break; + } + } + + virtual void pushR0() { + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); + switch(r0ct) { + case TY_INT: + o(0x50); /* push %eax */ + break; + case TY_FLOAT: + o(0x50); /* push %eax */ + o(0x241cd9); // fstps 0(%esp) + break; + case TY_DOUBLE: + o(0x50); /* push %eax */ + o(0x50); /* push %eax */ + o(0x241cdd); // fstpl 0(%esp) + break; + default: + error("pushR0 unsupported type %d", r0ct); + break; + } + pushType(); + } + + virtual void over() { + // We know it's only used for int-ptr ops (++/--) + + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); + + Type* pTOSType = getTOSType(); + TypeTag tosct = collapseType(pTOSType->tag); + + assert (r0ct == TY_INT && tosct == TY_INT); + + o(0x59); /* pop %ecx */ + o(0x50); /* push %eax */ + o(0x51); /* push %ecx */ + + overType(); + } + + virtual void popR0() { + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); + switch(r0ct) { + case TY_INT: + o(0x58); /* popl %eax */ + break; + case TY_FLOAT: + o(0x2404d9); // flds (%esp) + o(0x58); /* popl %eax */ + break; + case TY_DOUBLE: + o(0x2404dd); // fldl (%esp) + o(0x58); /* popl %eax */ + o(0x58); /* popl %eax */ + break; + default: + error("popR0 unsupported type %d", r0ct); + break; + } + popType(); + } + + virtual void storeR0ToTOS() { + Type* pPointerType = getTOSType(); + assert(pPointerType->tag == TY_POINTER); + Type* pTargetType = pPointerType->pHead; + convertR0(pTargetType); + o(0x59); /* pop %ecx */ + popType(); + switch (pTargetType->tag) { + case TY_POINTER: + case TY_INT: + o(0x0189); /* movl %eax/%al, (%ecx) */ + break; + case TY_SHORT: + o(0x018966); /* movw %ax, (%ecx) */ + break; + case TY_CHAR: + o(0x0188); /* movl %eax/%al, (%ecx) */ + break; + case TY_FLOAT: + o(0x19d9); /* fstps (%ecx) */ + break; + case TY_DOUBLE: + o(0x19dd); /* fstpl (%ecx) */ + break; + case TY_STRUCT: + { + // TODO: use alignment information to use movsw/movsl instead of movsb + int size = sizeOf(pTargetType); + if (size > 0) { + o(0x9c); // pushf + o(0x57); // pushl %edi + o(0x56); // pushl %esi + o(0xcf89); // movl %ecx, %edi + o(0xc689); // movl %eax, %esi + oad(0xb9, size); // mov #size, %ecx + o(0xfc); // cld + o(0xf3); // rep + o(0xa4); // movsb + o(0x5e); // popl %esi + o(0x5f); // popl %edi + o(0x9d); // popf + } + } + break; + default: + error("storeR0ToTOS: unsupported type %d", + pTargetType->tag); + break; + } + setR0Type(pTargetType); + } + + virtual void loadR0FromR0() { + Type* pPointerType = getR0Type(); + assert(pPointerType->tag == TY_POINTER); + Type* pNewType = pPointerType->pHead; + TypeTag tag = pNewType->tag; + switch (tag) { + case TY_POINTER: + case TY_INT: + o2(0x008b); /* mov (%eax), %eax */ + break; + case TY_SHORT: + o(0xbf0f); /* movswl (%eax), %eax */ + ob(0); + break; + case TY_CHAR: + o(0xbe0f); /* movsbl (%eax), %eax */ + ob(0); /* add zero in code */ + break; + case TY_FLOAT: + o2(0x00d9); // flds (%eax) + break; + case TY_DOUBLE: + o2(0x00dd); // fldl (%eax) + break; + case TY_ARRAY: + pNewType = pNewType->pTail; + break; + case TY_STRUCT: + break; + default: + error("loadR0FromR0: unsupported type %d", tag); + break; + } + setR0Type(pNewType); + } + + virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { + gmov(10, ea); /* leal EA, %eax */ + setR0Type(pPointerType, et); + } + + virtual int leaForward(int ea, Type* pPointerType) { + oad(0xb8, ea); /* mov $xx, %eax */ + setR0Type(pPointerType); + return getPC() - 4; + } + + virtual void convertR0Imp(Type* pType, bool isCast){ + Type* pR0Type = getR0Type(); + if (pR0Type == NULL) { + assert(false); + setR0Type(pType); + return; + } + if (isPointerType(pType) && isPointerType(pR0Type)) { + Type* pA = pR0Type; + Type* pB = pType; + // Array decays to pointer + if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) { + pA = pA->pTail; + } + if (! (typeEqual(pA, pB) + || pB->pHead->tag == TY_VOID + || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast) + )) { + error("Incompatible pointer or array types"); + } + } else if (bitsSame(pType, pR0Type)) { + // do nothing special + } else if (isFloatType(pType) && isFloatType(pR0Type)) { + // do nothing special, both held in same register on x87. + } else { + TypeTag r0Tag = collapseType(pR0Type->tag); + TypeTag destTag = collapseType(pType->tag); + if (r0Tag == TY_INT && isFloatTag(destTag)) { + // Convert R0 from int to float + o(0x50); // push %eax + o(0x2404DB); // fildl 0(%esp) + o(0x58); // pop %eax + } else if (isFloatTag(r0Tag) && destTag == TY_INT) { + // Convert R0 from float to int. Complicated because + // need to save and restore the rounding mode. + o(0x50); // push %eax + o(0x50); // push %eax + o(0x02247cD9); // fnstcw 2(%esp) + o(0x2444b70f); // movzwl 2(%esp), %eax + o(0x02); + o(0x0cb4); // movb $12, %ah + o(0x24048966); // movw %ax, 0(%esp) + o(0x242cd9); // fldcw 0(%esp) + o(0x04245cdb); // fistpl 4(%esp) + o(0x02246cd9); // fldcw 2(%esp) + o(0x58); // pop %eax + o(0x58); // pop %eax + } else { + error("Incompatible types old: %d new: %d", + pR0Type->tag, pType->tag); + } + } + setR0Type(pType); + } + + virtual int beginFunctionCallArguments() { + return oad(0xec81, 0); /* sub $xxx, %esp */ + } + + virtual size_t storeR0ToArg(int l, Type* pArgType) { + convertR0(pArgType); + Type* pR0Type = getR0Type(); + TypeTag r0ct = collapseType(pR0Type->tag); + switch(r0ct) { + case TY_INT: + oad(0x248489, l); /* movl %eax, xxx(%esp) */ + return 4; + case TY_FLOAT: + oad(0x249CD9, l); /* fstps xxx(%esp) */ + return 4; + case TY_DOUBLE: + oad(0x249CDD, l); /* fstpl xxx(%esp) */ + return 8; + default: + assert(false); + return 0; + } + } + + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { + * (int*) a = l; + } + + virtual int callForward(int symbol, Type* pFunc) { + assert(pFunc->tag == TY_FUNC); + setR0Type(pFunc->pHead); + return psym(0xe8, symbol); /* call xxx */ + } + + virtual void callIndirect(int l, Type* pFunc) { + assert(pFunc->tag == TY_FUNC); + popType(); // Get rid of indirect fn pointer type + setR0Type(pFunc->pHead); + oad(0x2494ff, l); /* call *xxx(%esp) */ + } + + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { + assert(pDecl->tag == TY_FUNC); + if (isIndirect) { + l += 4; + } + if (l > 0) { + oad(0xc481, l); /* add $xxx, %esp */ + } + } + + virtual int jumpOffset() { + return 5; + } + + /* output a symbol and patch all calls to it */ + virtual void gsym(int t) { + int n; + int pc = getPC(); + while (t) { + n = *(int *) t; /* next value */ + *(int *) t = pc - t - 4; + t = n; + } + } + + /* output a symbol and patch all calls to it, using absolute address */ + virtual void resolveForward(int t) { + int n; + int pc = getPC(); + while (t) { + n = *(int *) t; /* next value */ + *(int *) t = pc; + t = n; + } + } + + virtual int finishCompile() { + size_t pagesize = 4096; + size_t base = (size_t) getBase() & ~ (pagesize - 1); + size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1); + int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC); + if (err) { + error("mprotect() failed: %d", errno); + } + return err; + } + + /** + * Alignment (in bytes) for this type of data + */ + virtual size_t alignmentOf(Type* pType){ + switch (pType->tag) { + case TY_CHAR: + return 1; + case TY_SHORT: + return 2; + case TY_ARRAY: + return alignmentOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->alignment & 0x7fffffff; + case TY_FUNC: + error("alignment of func not supported"); + return 1; + default: + return 4; + } + } + + /** + * Array element alignment (in bytes) for this type of data. + */ + virtual size_t sizeOf(Type* pType){ + switch(pType->tag) { + case TY_INT: + return 4; + case TY_SHORT: + return 2; + case TY_CHAR: + return 1; + case TY_FLOAT: + return 4; + case TY_DOUBLE: + return 8; + case TY_POINTER: + return 4; + case TY_ARRAY: + return pType->length * sizeOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->length; + default: + error("Unsupported type %d", pType->tag); + return 0; + } + } + + private: + + /** Output 1 to 4 bytes. + * + */ + void o(int n) { + /* cannot use unsigned, so we must do a hack */ + while (n && n != -1) { + ob(n & 0xff); + n = n >> 8; + } + } + + /* Output exactly 2 bytes + */ + void o2(int n) { + ob(n & 0xff); + ob(0xff & (n >> 8)); + } + + /* psym is used to put an instruction with a data field which is a + reference to a symbol. It is in fact the same as oad ! */ + int psym(int n, int t) { + return oad(n, t); + } + + /* instruction + address */ + int oad(int n, int t) { + o(n); + int result = getPC(); + o4(t); + return result; + } + + static const int operatorHelper[]; + + int decodeOp(int op) { + if (op < 0 || op > OP_COUNT) { + error("Out-of-range operator: %d\n", op); + op = 0; + } + return operatorHelper[op]; + } + + void gmov(int l, int t) { + o(l + 0x83); + oad((t > -LOCAL && t < LOCAL) << 7 | 5, t); + } + + void setupFloatOperands() { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (! isFloatR0) { + // Convert R0 from int to float + o(0x50); // push %eax + o(0x2404DB); // fildl 0(%esp) + o(0x58); // pop %eax + } + if (! isFloatTOS){ + o(0x2404DB); // fildl 0(%esp); + o(0x58); // pop %eax + } else { + if (tagTOS == TY_FLOAT) { + o(0x2404d9); // flds (%esp) + o(0x58); // pop %eax + } else { + o(0x2404dd); // fldl (%esp) + o(0x58); // pop %eax + o(0x58); // pop %eax + } + } + popType(); + } + }; + +#endif // PROVIDE_X86_CODEGEN + +#ifdef PROVIDE_TRACE_CODEGEN + class TraceCodeGenerator : public CodeGenerator { + private: + CodeGenerator* mpBase; + + public: + TraceCodeGenerator(CodeGenerator* pBase) { + mpBase = pBase; + } + + virtual ~TraceCodeGenerator() { + delete mpBase; + } + + virtual void init(ICodeBuf* pCodeBuf) { + mpBase->init(pCodeBuf); + } + + void setErrorSink(ErrorSink* pErrorSink) { + mpBase->setErrorSink(pErrorSink); + } + + /* returns address to patch with local variable size + */ + virtual int functionEntry(Type* pDecl) { + int result = mpBase->functionEntry(pDecl); + fprintf(stderr, "functionEntry(pDecl) -> %d\n", result); + return result; + } + + virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { + fprintf(stderr, "functionExit(pDecl, %d, %d)\n", + localVariableAddress, localVariableSize); + mpBase->functionExit(pDecl, localVariableAddress, localVariableSize); + } + + /* load immediate value */ + virtual void li(int t) { + fprintf(stderr, "li(%d)\n", t); + mpBase->li(t); + } + + virtual void loadFloat(int address, Type* pType) { + fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag); + mpBase->loadFloat(address, pType); + } + + virtual void addStructOffsetR0(int offset, Type* pType) { + fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag); + mpBase->addStructOffsetR0(offset, pType); + } + + virtual int gjmp(int t) { + int result = mpBase->gjmp(t); + fprintf(stderr, "gjmp(%d) = %d\n", t, result); + return result; + } + + /* l = 0: je, l == 1: jne */ + virtual int gtst(bool l, int t) { + int result = mpBase->gtst(l, t); + fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result); + return result; + } + + virtual void gcmp(int op) { + fprintf(stderr, "gcmp(%d)\n", op); + mpBase->gcmp(op); + } + + virtual void genOp(int op) { + fprintf(stderr, "genOp(%d)\n", op); + mpBase->genOp(op); + } + + + virtual void gUnaryCmp(int op) { + fprintf(stderr, "gUnaryCmp(%d)\n", op); + mpBase->gUnaryCmp(op); + } + + virtual void genUnaryOp(int op) { + fprintf(stderr, "genUnaryOp(%d)\n", op); + mpBase->genUnaryOp(op); + } + + virtual void pushR0() { + fprintf(stderr, "pushR0()\n"); + mpBase->pushR0(); + } + + virtual void over() { + fprintf(stderr, "over()\n"); + mpBase->over(); + } + + virtual void popR0() { + fprintf(stderr, "popR0()\n"); + mpBase->popR0(); + } + + virtual void storeR0ToTOS() { + fprintf(stderr, "storeR0ToTOS()\n"); + mpBase->storeR0ToTOS(); + } + + virtual void loadR0FromR0() { + fprintf(stderr, "loadR0FromR0()\n"); + mpBase->loadR0FromR0(); + } + + virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { + fprintf(stderr, "leaR0(%d, %d, %d)\n", ea, + pPointerType->pHead->tag, et); + mpBase->leaR0(ea, pPointerType, et); + } + + virtual int leaForward(int ea, Type* pPointerType) { + fprintf(stderr, "leaForward(%d)\n", ea); + return mpBase->leaForward(ea, pPointerType); + } + + virtual void convertR0Imp(Type* pType, bool isCast){ + fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast); + mpBase->convertR0Imp(pType, isCast); + } + + virtual int beginFunctionCallArguments() { + int result = mpBase->beginFunctionCallArguments(); + fprintf(stderr, "beginFunctionCallArguments() = %d\n", result); + return result; + } + + virtual size_t storeR0ToArg(int l, Type* pArgType) { + fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l, + pArgType->tag); + return mpBase->storeR0ToArg(l, pArgType); + } + + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { + fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l); + mpBase->endFunctionCallArguments(pDecl, a, l); + } + + virtual int callForward(int symbol, Type* pFunc) { + int result = mpBase->callForward(symbol, pFunc); + fprintf(stderr, "callForward(%d) = %d\n", symbol, result); + return result; + } + + virtual void callIndirect(int l, Type* pFunc) { + fprintf(stderr, "callIndirect(%d returntype = %d)\n", l, + pFunc->pHead->tag); + mpBase->callIndirect(l, pFunc); + } + + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { + fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect); + mpBase->adjustStackAfterCall(pDecl, l, isIndirect); + } + + virtual int jumpOffset() { + return mpBase->jumpOffset(); + } + + /* output a symbol and patch all calls to it */ + virtual void gsym(int t) { + fprintf(stderr, "gsym(%d)\n", t); + mpBase->gsym(t); + } + + virtual void resolveForward(int t) { + mpBase->resolveForward(t); + } + + virtual int finishCompile() { + int result = mpBase->finishCompile(); + fprintf(stderr, "finishCompile() = %d\n", result); + return result; + } + + /** + * Alignment (in bytes) for this type of data + */ + virtual size_t alignmentOf(Type* pType){ + return mpBase->alignmentOf(pType); + } + + /** + * Array element alignment (in bytes) for this type of data. + */ + virtual size_t sizeOf(Type* pType){ + return mpBase->sizeOf(pType); + } + + virtual Type* getR0Type() { + return mpBase->getR0Type(); + } + + virtual ExpressionType getR0ExpressionType() { + return mpBase->getR0ExpressionType(); + } + + virtual void setR0ExpressionType(ExpressionType et) { + mpBase->setR0ExpressionType(et); + } + + virtual size_t getExpressionStackDepth() { + return mpBase->getExpressionStackDepth(); + } + + virtual void forceR0RVal() { + return mpBase->forceR0RVal(); + } + }; + +#endif // PROVIDE_TRACE_CODEGEN + + class Arena { + public: + // Used to record a given allocation amount. + // Used: + // Mark mark = arena.mark(); + // ... lots of arena.allocate() + // arena.free(mark); + + struct Mark { + size_t chunk; + size_t offset; + }; + + Arena() { + mCurrentChunk = 0; + Chunk start(CHUNK_SIZE); + mData.push_back(start); + } + + ~Arena() { + for(size_t i = 0; i < mData.size(); i++) { + mData[i].free(); + } + } + + // Alloc using the standard alignment size safe for any variable + void* alloc(size_t size) { + return alloc(size, 8); + } + + Mark mark(){ + Mark result; + result.chunk = mCurrentChunk; + result.offset = mData[mCurrentChunk].mOffset; + return result; + } + + void freeToMark(const Mark& mark) { + mCurrentChunk = mark.chunk; + mData[mCurrentChunk].mOffset = mark.offset; + } + + private: + // Allocate memory aligned to a given size + // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...) + // Memory is not zero filled. + + void* alloc(size_t size, size_t alignment) { + while (size > mData[mCurrentChunk].remainingCapacity(alignment)) { + if (mCurrentChunk + 1 < mData.size()) { + mCurrentChunk++; + } else { + size_t allocSize = CHUNK_SIZE; + if (allocSize < size + alignment - 1) { + allocSize = size + alignment - 1; + } + Chunk chunk(allocSize); + mData.push_back(chunk); + mCurrentChunk++; + } + } + return mData[mCurrentChunk].allocate(size, alignment); + } + + static const size_t CHUNK_SIZE = 128*1024; + // Note: this class does not deallocate its + // memory when it's destroyed. It depends upon + // its parent to deallocate the memory. + struct Chunk { + Chunk() { + mpData = 0; + mSize = 0; + mOffset = 0; + } + + Chunk(size_t size) { + mSize = size; + mpData = (char*) malloc(size); + mOffset = 0; + } + + ~Chunk() { + // Doesn't deallocate memory. + } + + void* allocate(size_t size, size_t alignment) { + size_t alignedOffset = aligned(mOffset, alignment); + void* result = mpData + alignedOffset; + mOffset = alignedOffset + size; + return result; + } + + void free() { + if (mpData) { + ::free(mpData); + mpData = 0; + } + } + + size_t remainingCapacity(size_t alignment) { + return aligned(mSize, alignment) - aligned(mOffset, alignment); + } + + // Assume alignment is a power of two + inline size_t aligned(size_t v, size_t alignment) { + size_t mask = alignment-1; + return (v + mask) & ~mask; + } + + char* mpData; + size_t mSize; + size_t mOffset; + }; + + size_t mCurrentChunk; + + Vector mData; + }; + + struct VariableInfo; + + struct Token { + int hash; + size_t length; + char* pText; + tokenid_t id; + + // Current values for the token + char* mpMacroDefinition; + VariableInfo* mpVariableInfo; + VariableInfo* mpStructInfo; + }; + + class TokenTable { + public: + // Don't use 0..0xff, allows characters and operators to be tokens too. + + static const int TOKEN_BASE = 0x100; + TokenTable() { + mpMap = hashmapCreate(128, hashFn, equalsFn); + } + + ~TokenTable() { + hashmapFree(mpMap); + } + + void setArena(Arena* pArena) { + mpArena = pArena; + } + + // Returns a token for a given string of characters. + tokenid_t intern(const char* pText, size_t length) { + Token probe; + int hash = hashmapHash((void*) pText, length); + { + Token probe; + probe.hash = hash; + probe.length = length; + probe.pText = (char*) pText; + Token* pValue = (Token*) hashmapGet(mpMap, &probe); + if (pValue) { + return pValue->id; + } + } + + Token* pToken = (Token*) mpArena->alloc(sizeof(Token)); + memset(pToken, 0, sizeof(*pToken)); + pToken->hash = hash; + pToken->length = length; + pToken->pText = (char*) mpArena->alloc(length + 1); + memcpy(pToken->pText, pText, length); + pToken->pText[length] = 0; + pToken->id = mTokens.size() + TOKEN_BASE; + mTokens.push_back(pToken); + hashmapPut(mpMap, pToken, pToken); + return pToken->id; + } + + // Return the Token for a given tokenid. + Token& operator[](tokenid_t id) { + return *mTokens[id - TOKEN_BASE]; + } + + inline size_t size() { + return mTokens.size(); + } + + private: + + static int hashFn(void* pKey) { + Token* pToken = (Token*) pKey; + return pToken->hash; + } + + static bool equalsFn(void* keyA, void* keyB) { + Token* pTokenA = (Token*) keyA; + Token* pTokenB = (Token*) keyB; + // Don't need to compare hash values, they should always be equal + return pTokenA->length == pTokenB->length + && strcmp(pTokenA->pText, pTokenB->pText) == 0; + } + + Hashmap* mpMap; + Vector mTokens; + Arena* mpArena; + }; + + class InputStream { + public: + virtual ~InputStream() {} + virtual int getChar() = 0; + }; + + class TextInputStream : public InputStream { + public: + TextInputStream(const char* text, size_t textLength) + : pText(text), mTextLength(textLength), mPosition(0) { + } + + virtual int getChar() { + return mPosition < mTextLength ? pText[mPosition++] : EOF; + } + + private: + const char* pText; + size_t mTextLength; + size_t mPosition; + }; + + class String { + public: + String() { + mpBase = 0; + mUsed = 0; + mSize = 0; + } + + String(const char* item, int len, bool adopt) { + if (len < 0) { + len = strlen(item); + } + if (adopt) { + mpBase = (char*) item; + mUsed = len; + mSize = len + 1; + } else { + mpBase = 0; + mUsed = 0; + mSize = 0; + appendBytes(item, len); + } + } + + String(const String& other) { + mpBase = 0; + mUsed = 0; + mSize = 0; + appendBytes(other.getUnwrapped(), other.len()); + } + + ~String() { + if (mpBase) { + free(mpBase); + } + } + + String& operator=(const String& other) { + clear(); + appendBytes(other.getUnwrapped(), other.len()); + return *this; + } + + inline char* getUnwrapped() const { + return mpBase; + } + + void clear() { + mUsed = 0; + if (mSize > 0) { + mpBase[0] = 0; + } + } + + void appendCStr(const char* s) { + appendBytes(s, strlen(s)); + } + + void appendBytes(const char* s, int n) { + memcpy(ensure(n), s, n + 1); + } + + void append(char c) { + * ensure(1) = c; + } + + void append(String& other) { + appendBytes(other.getUnwrapped(), other.len()); + } + + char* orphan() { + char* result = mpBase; + mpBase = 0; + mUsed = 0; + mSize = 0; + return result; + } + + void printf(const char* fmt,...) { + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } + + void vprintf(const char* fmt, va_list ap) { + char* temp; + int numChars = vasprintf(&temp, fmt, ap); + memcpy(ensure(numChars), temp, numChars+1); + free(temp); + } + + inline size_t len() const { + return mUsed; + } + + private: + char* ensure(int n) { + size_t newUsed = mUsed + n; + if (newUsed > mSize) { + size_t newSize = mSize * 2 + 10; + if (newSize < newUsed) { + newSize = newUsed; + } + mpBase = (char*) realloc(mpBase, newSize + 1); + mSize = newSize; + } + mpBase[newUsed] = '\0'; + char* result = mpBase + mUsed; + mUsed = newUsed; + return result; + } + + char* mpBase; + size_t mUsed; + size_t mSize; + }; + + void internKeywords() { + // Note: order has to match TOK_ constants + static const char* keywords[] = { + "int", + "char", + "void", + "if", + "else", + "while", + "break", + "return", + "for", + "auto", + "case", + "const", + "continue", + "default", + "do", + "double", + "enum", + "extern", + "float", + "goto", + "long", + "register", + "short", + "signed", + "sizeof", + "static", + "struct", + "switch", + "typedef", + "union", + "unsigned", + "volatile", + "_Bool", + "_Complex", + "_Imaginary", + "inline", + "restrict", + + // predefined tokens that can also be symbols start here: + "pragma", + "define", + "line", + 0}; + + for(int i = 0; keywords[i]; i++) { + mTokenTable.intern(keywords[i], strlen(keywords[i])); + } + } + + struct InputState { + InputStream* pStream; + int oldCh; + }; + + struct VariableInfo { + void* pAddress; + void* pForward; // For a forward direction, linked list of data to fix up + tokenid_t tok; + size_t level; + VariableInfo* pOldDefinition; + Type* pType; + bool isStructTag; + }; + + class SymbolStack { + public: + SymbolStack() { + mpArena = 0; + mpTokenTable = 0; + } + + void setArena(Arena* pArena) { + mpArena = pArena; + } + + void setTokenTable(TokenTable* pTokenTable) { + mpTokenTable = pTokenTable; + } + + void pushLevel() { + Mark mark; + mark.mArenaMark = mpArena->mark(); + mark.mSymbolHead = mStack.size(); + mLevelStack.push_back(mark); + } + + void popLevel() { + // Undo any shadowing that was done: + Mark mark = mLevelStack.back(); + mLevelStack.pop_back(); + while (mStack.size() > mark.mSymbolHead) { + VariableInfo* pV = mStack.back(); + mStack.pop_back(); + if (pV->isStructTag) { + (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition; + } else { + (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition; + } + } + mpArena->freeToMark(mark.mArenaMark); + } + + bool isDefinedAtCurrentLevel(tokenid_t tok) { + VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo; + return pV && pV->level == level(); + } + + bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) { + VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo; + return pV && pV->level == level(); + } + + VariableInfo* add(tokenid_t tok) { + Token& token = (*mpTokenTable)[tok]; + VariableInfo* pOldV = token.mpVariableInfo; + VariableInfo* pNewV = + (VariableInfo*) mpArena->alloc(sizeof(VariableInfo)); + memset(pNewV, 0, sizeof(VariableInfo)); + pNewV->tok = tok; + pNewV->level = level(); + pNewV->pOldDefinition = pOldV; + token.mpVariableInfo = pNewV; + mStack.push_back(pNewV); + return pNewV; + } + + VariableInfo* addStructTag(tokenid_t tok) { + Token& token = (*mpTokenTable)[tok]; + VariableInfo* pOldS = token.mpStructInfo; + VariableInfo* pNewS = + (VariableInfo*) mpArena->alloc(sizeof(VariableInfo)); + memset(pNewS, 0, sizeof(VariableInfo)); + pNewS->tok = tok; + pNewS->level = level(); + pNewS->isStructTag = true; + pNewS->pOldDefinition = pOldS; + token.mpStructInfo = pNewS; + mStack.push_back(pNewS); + return pNewS; + } + + VariableInfo* add(Type* pType) { + VariableInfo* pVI = add(pType->id); + pVI->pType = pType; + return pVI; + } + + void forEach(bool (*fn)(VariableInfo*, void*), void* context) { + for (size_t i = 0; i < mStack.size(); i++) { + if (! fn(mStack[i], context)) { + break; + } + } + } + + private: + inline size_t level() { + return mLevelStack.size(); + } + + struct Mark { + Arena::Mark mArenaMark; + size_t mSymbolHead; + }; + + Arena* mpArena; + TokenTable* mpTokenTable; + Vector mStack; + Vector mLevelStack; + }; + + int ch; // Current input character, or EOF + tokenid_t tok; // token + intptr_t tokc; // token extra info + double tokd; // floating point constant value + int tokl; // token operator level + intptr_t rsym; // return symbol + Type* pReturnType; // type of the current function's return. + intptr_t loc; // local variable index + char* glo; // global variable index + String mTokenString; + bool mbSuppressMacroExpansion; + char* dptr; // Macro state: Points to macro text during macro playback. + int dch; // Macro state: Saves old value of ch during a macro playback. + char* pGlobalBase; + ACCSymbolLookupFn mpSymbolLookupFn; + void* mpSymbolLookupContext; + + // Arena for the duration of the compile + Arena mGlobalArena; + // Arena for data that's only needed when compiling a single function + Arena mLocalArena; + + Arena* mpCurrentArena; + + TokenTable mTokenTable; + SymbolStack mGlobals; + SymbolStack mLocals; + + SymbolStack* mpCurrentSymbolStack; + + // Prebuilt types, makes things slightly faster. + Type* mkpInt; // int + Type* mkpShort; // short + Type* mkpChar; // char + Type* mkpVoid; // void + Type* mkpFloat; + Type* mkpDouble; + Type* mkpIntFn; + Type* mkpIntPtr; + Type* mkpCharPtr; + Type* mkpFloatPtr; + Type* mkpDoublePtr; + Type* mkpPtrIntFn; + + InputStream* file; + int mLineNumber; + bool mbBumpLine; + + ICodeBuf* pCodeBuf; + CodeGenerator* pGen; + + String mErrorBuf; + + String mPragmas; + int mPragmaStringCount; + int mCompileResult; + + static const int ALLOC_SIZE = 99999; + + static const int TOK_DUMMY = 1; + static const int TOK_NUM = 2; + static const int TOK_NUM_FLOAT = 3; + static const int TOK_NUM_DOUBLE = 4; + static const int TOK_OP_ASSIGNMENT = 5; + static const int TOK_OP_ARROW = 6; + + // 3..255 are character and/or operators + + // Keywords start at 0x100 and increase by 1 + // Order has to match string list in "internKeywords". + enum { + TOK_KEYWORD = TokenTable::TOKEN_BASE, + TOK_INT = TOK_KEYWORD, + TOK_CHAR, + TOK_VOID, + TOK_IF, + TOK_ELSE, + TOK_WHILE, + TOK_BREAK, + TOK_RETURN, + TOK_FOR, + TOK_AUTO, + TOK_CASE, + TOK_CONST, + TOK_CONTINUE, + TOK_DEFAULT, + TOK_DO, + TOK_DOUBLE, + TOK_ENUM, + TOK_EXTERN, + TOK_FLOAT, + TOK_GOTO, + TOK_LONG, + TOK_REGISTER, + TOK_SHORT, + TOK_SIGNED, + TOK_SIZEOF, + TOK_STATIC, + TOK_STRUCT, + TOK_SWITCH, + TOK_TYPEDEF, + TOK_UNION, + TOK_UNSIGNED, + TOK_VOLATILE, + TOK__BOOL, + TOK__COMPLEX, + TOK__IMAGINARY, + TOK_INLINE, + TOK_RESTRICT, + + // Symbols start after keywords + + TOK_SYMBOL, + TOK_PRAGMA = TOK_SYMBOL, + TOK_DEFINE, + TOK_LINE + }; + + static const int LOCAL = 0x200; + + static const int SYM_FORWARD = 0; + static const int SYM_DEFINE = 1; + + /* tokens in string heap */ + static const int TAG_TOK = ' '; + + static const int OP_INCREMENT = 0; + static const int OP_DECREMENT = 1; + static const int OP_MUL = 2; + static const int OP_DIV = 3; + static const int OP_MOD = 4; + static const int OP_PLUS = 5; + static const int OP_MINUS = 6; + static const int OP_SHIFT_LEFT = 7; + static const int OP_SHIFT_RIGHT = 8; + static const int OP_LESS_EQUAL = 9; + static const int OP_GREATER_EQUAL = 10; + static const int OP_LESS = 11; + static const int OP_GREATER = 12; + static const int OP_EQUALS = 13; + static const int OP_NOT_EQUALS = 14; + static const int OP_LOGICAL_AND = 15; + static const int OP_LOGICAL_OR = 16; + static const int OP_BIT_AND = 17; + static const int OP_BIT_XOR = 18; + static const int OP_BIT_OR = 19; + static const int OP_BIT_NOT = 20; + static const int OP_LOGICAL_NOT = 21; + static const int OP_COUNT = 22; + + /* Operators are searched from front, the two-character operators appear + * before the single-character operators with the same first character. + * @ is used to pad out single-character operators. + */ + static const char* operatorChars; + static const char operatorLevel[]; + + /* Called when we detect an internal problem. Does nothing in production. + * + */ + void internalError() { + * (char*) 0 = 0; + } + + void assertImpl(bool isTrue, int line) { + if (!isTrue) { + LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line); + internalError(); + } + } + + bool isSymbol(tokenid_t t) { + return t >= TOK_SYMBOL && + ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size(); + } + + bool isSymbolOrKeyword(tokenid_t t) { + return t >= TOK_KEYWORD && + ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size(); + } + + VariableInfo* VI(tokenid_t t) { + assert(isSymbol(t)); + VariableInfo* pV = mTokenTable[t].mpVariableInfo; + if (pV && pV->tok != t) { + internalError(); + } + return pV; + } + + inline bool isDefined(tokenid_t t) { + return t >= TOK_SYMBOL && VI(t) != 0; + } + + const char* nameof(tokenid_t t) { + assert(isSymbolOrKeyword(t)); + return mTokenTable[t].pText; + } + + void pdef(int t) { + mTokenString.append(t); + } + + void inp() { + if (dptr) { + ch = *dptr++; + if (ch == 0) { + dptr = 0; + ch = dch; + } + } else { + if (mbBumpLine) { + mLineNumber++; + mbBumpLine = false; + } + ch = file->getChar(); + if (ch == '\n') { + mbBumpLine = true; + } + } +#if 0 + printf("ch='%c' 0x%x\n", ch, ch); +#endif + } + + int isid() { + return isalnum(ch) | (ch == '_'); + } + + int decodeHex(int c) { + if (isdigit(c)) { + c -= '0'; + } else if (c <= 'F') { + c = c - 'A' + 10; + } else { + c =c - 'a' + 10; + } + return c; + } + + /* read a character constant, advances ch to after end of constant */ + int getq() { + int val = ch; + if (ch == '\\') { + inp(); + if (isoctal(ch)) { + // 1 to 3 octal characters. + val = 0; + for(int i = 0; i < 3; i++) { + if (isoctal(ch)) { + val = (val << 3) + ch - '0'; + inp(); + } + } + return val; + } else if (ch == 'x' || ch == 'X') { + // N hex chars + inp(); + if (! isxdigit(ch)) { + error("'x' character escape requires at least one digit."); + } else { + val = 0; + while (isxdigit(ch)) { + val = (val << 4) + decodeHex(ch); + inp(); + } + } + } else { + int val = ch; + switch (ch) { + case 'a': + val = '\a'; + break; + case 'b': + val = '\b'; + break; + case 'f': + val = '\f'; + break; + case 'n': + val = '\n'; + break; + case 'r': + val = '\r'; + break; + case 't': + val = '\t'; + break; + case 'v': + val = '\v'; + break; + case '\\': + val = '\\'; + break; + case '\'': + val = '\''; + break; + case '"': + val = '"'; + break; + case '?': + val = '?'; + break; + default: + error("Undefined character escape %c", ch); + break; + } + inp(); + return val; + } + } else { + inp(); + } + return val; + } + + static bool isoctal(int ch) { + return ch >= '0' && ch <= '7'; + } + + bool acceptCh(int c) { + bool result = c == ch; + if (result) { + pdef(ch); + inp(); + } + return result; + } + + bool acceptDigitsCh() { + bool result = false; + while (isdigit(ch)) { + result = true; + pdef(ch); + inp(); + } + return result; + } + + void parseFloat() { + tok = TOK_NUM_DOUBLE; + // mTokenString already has the integral part of the number. + if(mTokenString.len() == 0) { + mTokenString.append('0'); + } + acceptCh('.'); + acceptDigitsCh(); + if (acceptCh('e') || acceptCh('E')) { + acceptCh('-') || acceptCh('+'); + acceptDigitsCh(); + } + if (ch == 'f' || ch == 'F') { + tok = TOK_NUM_FLOAT; + inp(); + } else if (ch == 'l' || ch == 'L') { + inp(); + error("Long floating point constants not supported."); + } + char* pText = mTokenString.getUnwrapped(); + char* pEnd = pText + strlen(pText); + char* pEndPtr = 0; + errno = 0; + if (tok == TOK_NUM_FLOAT) { + tokd = strtof(pText, &pEndPtr); + } else { + tokd = strtod(pText, &pEndPtr); + } + if (errno || pEndPtr != pEnd) { + error("Can't parse constant: %s", pText); + } + // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd); + } + + void next() { + int l, a; + + while (isspace(ch) | (ch == '#')) { + if (ch == '#') { + inp(); + next(); + if (tok == TOK_DEFINE) { + doDefine(); + } else if (tok == TOK_PRAGMA) { + doPragma(); + } else if (tok == TOK_LINE) { + doLine(); + } else { + error("Unsupported preprocessor directive \"%s\"", + mTokenString.getUnwrapped()); + } + } + inp(); + } + tokl = 0; + tok = ch; + /* encode identifiers & numbers */ + if (isdigit(ch) || ch == '.') { + // Start of a numeric constant. Could be integer, float, or + // double, won't know until we look further. + mTokenString.clear(); + pdef(ch); + inp(); + if (tok == '.' && !isdigit(ch)) { + goto done; + } + int base = 10; + if (tok == '0') { + if (ch == 'x' || ch == 'X') { + base = 16; + tok = TOK_NUM; + tokc = 0; + inp(); + while ( isxdigit(ch) ) { + tokc = (tokc << 4) + decodeHex(ch); + inp(); + } + } else if (isoctal(ch)){ + base = 8; + tok = TOK_NUM; + tokc = 0; + while ( isoctal(ch) ) { + tokc = (tokc << 3) + (ch - '0'); + inp(); + } + } + } else if (isdigit(tok)){ + acceptDigitsCh(); + } + if (base == 10) { + if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') { + parseFloat(); + } else { + // It's an integer constant + char* pText = mTokenString.getUnwrapped(); + char* pEnd = pText + strlen(pText); + char* pEndPtr = 0; + errno = 0; + tokc = strtol(pText, &pEndPtr, base); + if (errno || pEndPtr != pEnd) { + error("Can't parse constant: %s %d %d", pText, base, errno); + } + tok = TOK_NUM; + } + } + } else if (isid()) { + mTokenString.clear(); + while (isid()) { + pdef(ch); + inp(); + } + tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len()); + if (! mbSuppressMacroExpansion) { + // Is this a macro? + char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition; + if (pMacroDefinition) { + // Yes, it is a macro + dptr = pMacroDefinition; + dch = ch; + inp(); + next(); + } + } + } else { + inp(); + if (tok == '\'') { + tok = TOK_NUM; + tokc = getq(); + if (ch != '\'') { + error("Expected a ' character, got %c", ch); + } else { + inp(); + } + } else if ((tok == '/') & (ch == '*')) { + inp(); + while (ch && ch != EOF) { + while (ch != '*' && ch != EOF) + inp(); + inp(); + if (ch == '/') + ch = 0; + } + if (ch == EOF) { + error("End of file inside comment."); + } + inp(); + next(); + } else if ((tok == '/') & (ch == '/')) { + inp(); + while (ch && (ch != '\n') && (ch != EOF)) { + inp(); + } + inp(); + next(); + } else if ((tok == '-') & (ch == '>')) { + inp(); + tok = TOK_OP_ARROW; + } else { + const char* t = operatorChars; + int opIndex = 0; + while ((l = *t++) != 0) { + a = *t++; + tokl = operatorLevel[opIndex]; + tokc = opIndex; + if ((l == tok) & ((a == ch) | (a == '@'))) { +#if 0 + printf("%c%c -> tokl=%d tokc=0x%x\n", + l, a, tokl, tokc); +#endif + if (a == ch) { + inp(); + tok = TOK_DUMMY; /* dummy token for double tokens */ + } + /* check for op=, valid for * / % + - << >> & ^ | */ + if (ch == '=' && + ((tokl >= 1 && tokl <= 3) + || (tokl >=6 && tokl <= 8)) ) { + inp(); + tok = TOK_OP_ASSIGNMENT; + } + break; + } + opIndex++; + } + if (l == 0) { + tokl = 0; + tokc = 0; + } + } + } + + done: ; +#if 0 + { + String buf; + decodeToken(buf, tok, true); + fprintf(stderr, "%s\n", buf.getUnwrapped()); + } +#endif + } + + void doDefine() { + mbSuppressMacroExpansion = true; + next(); + mbSuppressMacroExpansion = false; + tokenid_t name = tok; + String* pName = new String(); + if (ch == '(') { + delete pName; + error("Defines with arguments not supported"); + return; + } + while (isspace(ch)) { + inp(); + } + String value; + bool appendToValue = true; + while (ch != '\n' && ch != EOF) { + // Check for '//' comments. + if (appendToValue && ch == '/') { + inp(); + if (ch == '/') { + appendToValue = false; + } else { + value.append('/'); + } + } + if (appendToValue && ch != EOF) { + value.append(ch); + } + inp(); + } + char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1); + memcpy(pDefn, value.getUnwrapped(), value.len()); + pDefn[value.len()] = 0; + mTokenTable[name].mpMacroDefinition = pDefn; + } + + void doPragma() { + // # pragma name(val) + int state = 0; + while(ch != EOF && ch != '\n' && state < 10) { + switch(state) { + case 0: + if (isspace(ch)) { + inp(); + } else { + state++; + } + break; + case 1: + if (isalnum(ch)) { + mPragmas.append(ch); + inp(); + } else if (ch == '(') { + mPragmas.append(0); + inp(); + state++; + } else { + state = 11; + } + break; + case 2: + if (isalnum(ch)) { + mPragmas.append(ch); + inp(); + } else if (ch == ')') { + mPragmas.append(0); + inp(); + state = 10; + } else { + state = 11; + } + break; + } + } + if(state != 10) { + error("Unexpected pragma syntax"); + } + mPragmaStringCount += 2; + } + + void doLine() { + // # line number { "filename "} + next(); + if (tok != TOK_NUM) { + error("Expected a line-number"); + } else { + mLineNumber = tokc-1; // The end-of-line will increment it. + } + while(ch != EOF && ch != '\n') { + inp(); + } + } + + virtual void verror(const char* fmt, va_list ap) { + mErrorBuf.printf("%ld: ", mLineNumber); + mErrorBuf.vprintf(fmt, ap); + mErrorBuf.printf("\n"); + } + + void skip(intptr_t c) { + if (!accept(c)) { + error("'%c' expected", c); + } + } + + bool accept(intptr_t c) { + if (tok == c) { + next(); + return true; + } + return false; + } + + bool acceptStringLiteral() { + if (tok == '"') { + pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE); + // This while loop merges multiple adjacent string constants. + while (tok == '"') { + while (ch != '"' && ch != EOF) { + *allocGlobalSpace(1,1) = getq(); + } + if (ch != '"') { + error("Unterminated string constant."); + } + inp(); + next(); + } + /* Null terminate */ + *glo = 0; + /* align heap */ + allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo); + + return true; + } + return false; + } + + void linkGlobal(tokenid_t t, bool isFunction) { + VariableInfo* pVI = VI(t); + void* n = NULL; + if (mpSymbolLookupFn) { + n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t)); + } + if (pVI->pType == NULL) { + if (isFunction) { + pVI->pType = mkpIntFn; + } else { + pVI->pType = mkpInt; + } + } + pVI->pAddress = n; + } + + void unaryOrAssignment() { + unary(); + if (accept('=')) { + checkLVal(); + pGen->pushR0(); + expr(); + pGen->forceR0RVal(); + pGen->storeR0ToTOS(); + } else if (tok == TOK_OP_ASSIGNMENT) { + int t = tokc; + next(); + checkLVal(); + pGen->pushR0(); + pGen->forceR0RVal(); + pGen->pushR0(); + expr(); + pGen->forceR0RVal(); + pGen->genOp(t); + pGen->storeR0ToTOS(); + } + } + + /* Parse and evaluate a unary expression. + */ + void unary() { + tokenid_t t; + intptr_t a; + t = 0; + if (acceptStringLiteral()) { + // Nothing else to do. + } else { + int c = tokl; + a = tokc; + double ad = tokd; + t = tok; + next(); + if (t == TOK_NUM) { + pGen->li(a); + } else if (t == TOK_NUM_FLOAT) { + // Align to 4-byte boundary + glo = (char*) (((intptr_t) glo + 3) & -4); + * (float*) glo = (float) ad; + pGen->loadFloat((int) glo, mkpFloat); + glo += 4; + } else if (t == TOK_NUM_DOUBLE) { + // Align to 8-byte boundary + glo = (char*) (((intptr_t) glo + 7) & -8); + * (double*) glo = ad; + pGen->loadFloat((int) glo, mkpDouble); + glo += 8; + } else if (c == 2) { + /* -, +, !, ~ */ + unary(); + pGen->forceR0RVal(); + if (t == '!') + pGen->gUnaryCmp(a); + else if (t == '+') { + // ignore unary plus. + } else { + pGen->genUnaryOp(a); + } + } else if (c == 11) { + // pre increment / pre decrement + unary(); + doIncDec(a == OP_INCREMENT, 0); + } + else if (t == '(') { + // It's either a cast or an expression + Type* pCast = acceptCastTypeDeclaration(); + if (pCast) { + skip(')'); + unary(); + pGen->forceR0RVal(); + pGen->castR0(pCast); + } else { + commaExpr(); + skip(')'); + } + } else if (t == '*') { + /* This is a pointer dereference. + */ + unary(); + doPointer(); + } else if (t == '&') { + unary(); + doAddressOf(); + } else if (t == EOF ) { + error("Unexpected EOF."); + } else if (t == ';') { + error("Unexpected ';'"); + } else if (!checkSymbol(t)) { + // Don't have to do anything special here, the error + // message was printed by checkSymbol() above. + } else { + if (!isDefined(t)) { + mGlobals.add(t); + // printf("Adding new global function %s\n", nameof(t)); + } + VariableInfo* pVI = VI(t); + int n = (intptr_t) pVI->pAddress; + /* forward reference: try our lookup function */ + if (!n) { + linkGlobal(t, tok == '('); + n = (intptr_t) pVI->pAddress; + if (!n && tok != '(') { + error("Undeclared variable %s", nameof(t)); + } + } + if (tok != '(') { + /* variable or function name */ + if (!n) { + linkGlobal(t, false); + n = (intptr_t) pVI->pAddress; + if (!n) { + error("Undeclared variable %s", nameof(t)); + } + } + } + // load a variable + Type* pVal; + ExpressionType et; + if (pVI->pType->tag == TY_ARRAY) { + pVal = pVI->pType; + et = ET_RVALUE; + } else { + pVal = createPtrType(pVI->pType); + et = ET_LVALUE; + } + if (n) { + int tag = pVal->pHead->tag; + if (tag == TY_FUNC) { + et = ET_RVALUE; + } + pGen->leaR0(n, pVal, et); + } else { + pVI->pForward = (void*) pGen->leaForward( + (int) pVI->pForward, pVal); + } + } + } + + /* Now handle postfix operators */ + for(;;) { + if (tokl == 11) { + // post inc / post dec + doIncDec(tokc == OP_INCREMENT, true); + next(); + } else if (accept('[')) { + // Array reference + pGen->forceR0RVal(); + pGen->pushR0(); + commaExpr(); + pGen->forceR0RVal(); + pGen->genOp(OP_PLUS); + doPointer(); + skip(']'); + } else if (accept('.')) { + // struct element + pGen->forceR0RVal(); + Type* pStruct = pGen->getR0Type(); + if (pStruct->tag == TY_STRUCT) { + doStructMember(pStruct, true); + } else { + error("expected a struct value to the left of '.'"); + } + } else if (accept(TOK_OP_ARROW)) { + pGen->forceR0RVal(); + Type* pPtr = pGen->getR0Type(); + if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) { + pGen->loadR0FromR0(); + doStructMember(pPtr->pHead, false); + } else { + error("Expected a pointer to a struct to the left of '->'"); + } + } else if (accept('(')) { + /* function call */ + Type* pDecl = NULL; + VariableInfo* pVI = NULL; + Type* pFn = pGen->getR0Type(); + assert(pFn->tag == TY_POINTER); + assert(pFn->pHead->tag == TY_FUNC); + pDecl = pFn->pHead; + pGen->pushR0(); + Type* pArgList = pDecl->pTail; + bool varArgs = pArgList == NULL; + /* push args and invert order */ + a = pGen->beginFunctionCallArguments(); + int l = 0; + int argCount = 0; + while (tok != ')' && tok != EOF) { + if (! varArgs && !pArgList) { + error("Unexpected argument."); + } + expr(); + pGen->forceR0RVal(); + Type* pTargetType; + if (pArgList) { + pTargetType = pArgList->pHead; + pArgList = pArgList->pTail; + } else { + // This is a ... function, just pass arguments in their + // natural type. + pTargetType = pGen->getR0Type(); + if (pTargetType->tag == TY_FLOAT) { + pTargetType = mkpDouble; + } else if (pTargetType->tag == TY_ARRAY) { + // Pass arrays by pointer. + pTargetType = pTargetType->pTail; + } + } + if (pTargetType->tag == TY_VOID) { + error("Can't pass void value for argument %d", + argCount + 1); + } else { + l += pGen->storeR0ToArg(l, pTargetType); + } + if (accept(',')) { + // fine + } else if ( tok != ')') { + error("Expected ',' or ')'"); + } + argCount += 1; + } + if (! varArgs && pArgList) { + error("Expected more argument(s). Saw %d", argCount); + } + pGen->endFunctionCallArguments(pDecl, a, l); + skip(')'); + pGen->callIndirect(l, pDecl); + pGen->adjustStackAfterCall(pDecl, l, true); + } else { + break; + } + } + } + + void doStructMember(Type* pStruct, bool isDot) { + Type* pStructElement = lookupStructMember(pStruct, tok); + if (pStructElement) { + next(); + pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead)); + } else { + String buf; + decodeToken(buf, tok, true); + error("Expected a struct member to the right of '%s', got %s", + isDot ? "." : "->", buf.getUnwrapped()); + } + } + + void doIncDec(int isInc, int isPost) { + // R0 already has the lval + checkLVal(); + int lit = isInc ? 1 : -1; + pGen->pushR0(); + pGen->loadR0FromR0(); + int tag = pGen->getR0Type()->tag; + if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR || + tag == TY_POINTER)) { + error("++/-- illegal for this type. %d", tag); + } + if (isPost) { + pGen->over(); + pGen->pushR0(); + pGen->li(lit); + pGen->genOp(OP_PLUS); + pGen->storeR0ToTOS(); + pGen->popR0(); + } else { + pGen->pushR0(); + pGen->li(lit); + pGen->genOp(OP_PLUS); + pGen->over(); + pGen->storeR0ToTOS(); + pGen->popR0(); + } + } + + void doPointer() { + pGen->forceR0RVal(); + Type* pR0Type = pGen->getR0Type(); + if (pR0Type->tag != TY_POINTER) { + error("Expected a pointer type."); + } else { + if (pR0Type->pHead->tag != TY_FUNC) { + pGen->setR0ExpressionType(ET_LVALUE); + } + } + } + + void doAddressOf() { + Type* pR0 = pGen->getR0Type(); + bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC; + if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) { + error("Expected an lvalue"); + } + Type* pR0Type = pGen->getR0Type(); + pGen->setR0ExpressionType(ET_RVALUE); + } + + /* Recursive descent parser for binary operations. + */ + void binaryOp(int level) { + intptr_t t, a; + t = 0; + if (level-- == 1) + unaryOrAssignment(); + else { + binaryOp(level); + a = 0; + while (level == tokl) { + t = tokc; + next(); + pGen->forceR0RVal(); + if (level > 8) { + a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */ + binaryOp(level); + } else { + pGen->pushR0(); + binaryOp(level); + // Check for syntax error. + if (pGen->getR0Type() == NULL) { + // We failed to parse a right-hand argument. + // Push a dummy value so we don't fail + pGen->li(0); + } + pGen->forceR0RVal(); + if ((level == 4) | (level == 5)) { + pGen->gcmp(t); + } else { + pGen->genOp(t); + } + } + } + /* && and || output code generation */ + if (a && level > 8) { + pGen->forceR0RVal(); + a = pGen->gtst(t == OP_LOGICAL_OR, a); + pGen->li(t != OP_LOGICAL_OR); + int b = pGen->gjmp(0); + pGen->gsym(a); + pGen->li(t == OP_LOGICAL_OR); + pGen->gsym(b); + } + } + } + + void commaExpr() { + for(;;) { + expr(); + if (!accept(',')) { + break; + } + } + } + + void expr() { + binaryOp(11); + } + + int test_expr() { + commaExpr(); + pGen->forceR0RVal(); + return pGen->gtst(0, 0); + } + + void block(intptr_t l, bool outermostFunctionBlock) { + intptr_t a, n, t; + + Type* pBaseType; + if ((pBaseType = acceptPrimitiveType())) { + /* declarations */ + localDeclarations(pBaseType); + } else if (tok == TOK_IF) { + next(); + skip('('); + a = test_expr(); + skip(')'); + block(l, false); + if (tok == TOK_ELSE) { + next(); + n = pGen->gjmp(0); /* jmp */ + pGen->gsym(a); + block(l, false); + pGen->gsym(n); /* patch else jmp */ + } else { + pGen->gsym(a); /* patch if test */ + } + } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) { + t = tok; + next(); + skip('('); + if (t == TOK_WHILE) { + n = pCodeBuf->getPC(); // top of loop, target of "next" iteration + a = test_expr(); + } else { + if (tok != ';') + commaExpr(); + skip(';'); + n = pCodeBuf->getPC(); + a = 0; + if (tok != ';') + a = test_expr(); + skip(';'); + if (tok != ')') { + t = pGen->gjmp(0); + commaExpr(); + pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); + pGen->gsym(t); + n = t + 4; + } + } + skip(')'); + block((intptr_t) &a, false); + pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */ + pGen->gsym(a); + } else if (tok == '{') { + if (! outermostFunctionBlock) { + mLocals.pushLevel(); + } + next(); + while (tok != '}' && tok != EOF) + block(l, false); + skip('}'); + if (! outermostFunctionBlock) { + mLocals.popLevel(); + } + } else { + if (accept(TOK_RETURN)) { + if (tok != ';') { + commaExpr(); + pGen->forceR0RVal(); + if (pReturnType->tag == TY_VOID) { + error("Must not return a value from a void function"); + } else { + pGen->convertR0(pReturnType); + } + } else { + if (pReturnType->tag != TY_VOID) { + error("Must specify a value here"); + } + } + rsym = pGen->gjmp(rsym); /* jmp */ + } else if (accept(TOK_BREAK)) { + *(int *) l = pGen->gjmp(*(int *) l); + } else if (tok != ';') + commaExpr(); + skip(';'); + } + } + + static bool typeEqual(Type* a, Type* b) { + if (a == b) { + return true; + } + if (a == NULL || b == NULL) { + return false; + } + TypeTag at = a->tag; + if (at != b->tag) { + return false; + } + if (at == TY_POINTER) { + return typeEqual(a->pHead, b->pHead); + } else if (at == TY_ARRAY) { + return a->length == b->length && typeEqual(a->pHead, b->pHead); + } else if (at == TY_FUNC || at == TY_PARAM) { + return typeEqual(a->pHead, b->pHead) + && typeEqual(a->pTail, b->pTail); + } else if (at == TY_STRUCT) { + return a->pHead == b->pHead; + } + return true; + } + + Type* createType(TypeTag tag, Type* pHead, Type* pTail) { + assert(tag >= TY_INT && tag <= TY_PARAM); + Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type)); + memset(pType, 0, sizeof(*pType)); + pType->tag = tag; + pType->pHead = pHead; + pType->pTail = pTail; + return pType; + } + + Type* createPtrType(Type* pType) { + return createType(TY_POINTER, pType, NULL); + } + + /** + * Try to print a type in declaration order + */ + void decodeType(String& buffer, Type* pType) { + buffer.clear(); + if (pType == NULL) { + buffer.appendCStr("null"); + return; + } + decodeTypeImp(buffer, pType); + } + + void decodeTypeImp(String& buffer, Type* pType) { + decodeTypeImpPrefix(buffer, pType); + decodeId(buffer, pType->id); + decodeTypeImpPostfix(buffer, pType); + } + + void decodeId(String& buffer, tokenid_t id) { + if (id) { + String temp; + decodeToken(temp, id, false); + buffer.append(temp); + } + } + + void decodeTypeImpPrefix(String& buffer, Type* pType) { + TypeTag tag = pType->tag; + + if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) { + switch (tag) { + case TY_INT: + buffer.appendCStr("int"); + break; + case TY_SHORT: + buffer.appendCStr("short"); + break; + case TY_CHAR: + buffer.appendCStr("char"); + break; + case TY_VOID: + buffer.appendCStr("void"); + break; + case TY_FLOAT: + buffer.appendCStr("float"); + break; + case TY_DOUBLE: + buffer.appendCStr("double"); + break; + case TY_STRUCT: + { + bool isStruct = (pType->pHead->alignment & 0x80000000) != 0; + buffer.appendCStr(isStruct ? "struct" : "union"); + if (pType->pHead && pType->pHead->structTag) { + buffer.append(' '); + decodeId(buffer, pType->pHead->structTag); + } + } + break; + default: + break; + } + buffer.append(' '); + } + + switch (tag) { + case TY_INT: + break; + case TY_SHORT: + break; + case TY_CHAR: + break; + case TY_VOID: + break; + case TY_FLOAT: + break; + case TY_DOUBLE: + break; + case TY_POINTER: + decodeTypeImpPrefix(buffer, pType->pHead); + if(pType->pHead && pType->pHead->tag == TY_FUNC) { + buffer.append('('); + } + buffer.append('*'); + break; + case TY_ARRAY: + decodeTypeImpPrefix(buffer, pType->pHead); + break; + case TY_STRUCT: + break; + case TY_FUNC: + decodeTypeImp(buffer, pType->pHead); + break; + case TY_PARAM: + decodeTypeImp(buffer, pType->pHead); + break; + default: + String temp; + temp.printf("Unknown tag %d", pType->tag); + buffer.append(temp); + break; + } + } + + void decodeTypeImpPostfix(String& buffer, Type* pType) { + TypeTag tag = pType->tag; + + switch(tag) { + case TY_POINTER: + if(pType->pHead && pType->pHead->tag == TY_FUNC) { + buffer.append(')'); + } + decodeTypeImpPostfix(buffer, pType->pHead); + break; + case TY_ARRAY: + { + String temp; + temp.printf("[%d]", pType->length); + buffer.append(temp); + } + break; + case TY_STRUCT: + if (pType->pHead->length >= 0) { + buffer.appendCStr(" {"); + for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) { + decodeTypeImp(buffer, pArg->pHead); + buffer.appendCStr(";"); + } + buffer.append('}'); + } + break; + case TY_FUNC: + buffer.append('('); + for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) { + decodeTypeImp(buffer, pArg); + if (pArg->pTail) { + buffer.appendCStr(", "); + } + } + buffer.append(')'); + break; + default: + break; + } + } + + void printType(Type* pType) { + String buffer; + decodeType(buffer, pType); + fprintf(stderr, "%s\n", buffer.getUnwrapped()); + } + + Type* acceptPrimitiveType() { + Type* pType; + if (tok == TOK_INT) { + pType = mkpInt; + } else if (tok == TOK_SHORT) { + pType = mkpShort; + } else if (tok == TOK_CHAR) { + pType = mkpChar; + } else if (tok == TOK_VOID) { + pType = mkpVoid; + } else if (tok == TOK_FLOAT) { + pType = mkpFloat; + } else if (tok == TOK_DOUBLE) { + pType = mkpDouble; + } else if (tok == TOK_STRUCT || tok == TOK_UNION) { + return acceptStruct(); + } else { + return NULL; + } + next(); + return pType; + } + + Type* acceptStruct() { + assert(tok == TOK_STRUCT || tok == TOK_UNION); + bool isStruct = tok == TOK_STRUCT; + next(); + tokenid_t structTag = acceptSymbol(); + bool isDeclaration = accept('{'); + bool fail = false; + + Type* pStructType = createType(TY_STRUCT, NULL, NULL); + if (structTag) { + Token* pToken = &mTokenTable[structTag]; + VariableInfo* pStructInfo = pToken->mpStructInfo; + bool needToDeclare = !pStructInfo; + if (pStructInfo) { + if (isDeclaration) { + if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) { + if (pStructInfo->pType->pHead->length == -1) { + // we're filling in a forward declaration. + needToDeclare = false; + } else { + error("A struct with the same name is already defined at this level."); + fail = true; + } + } else { + needToDeclare = true; + } + } + if (!fail) { + assert(pStructInfo->isStructTag); + pStructType->pHead = pStructInfo->pType; + pStructType->pTail = pStructType->pHead->pTail; + } + } + + if (needToDeclare) { + // This is a new struct name + pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag); + pStructType = createType(TY_STRUCT, NULL, NULL); + pStructType->structTag = structTag; + pStructType->pHead = pStructType; + if (! isDeclaration) { + // A forward declaration + pStructType->length = -1; + } + pToken->mpStructInfo->pType = pStructType; + } + } else { + // An anonymous struct + pStructType->pHead = pStructType; + } + + if (isDeclaration) { + size_t offset = 0; + size_t structSize = 0; + size_t structAlignment = 0; + Type** pParamHolder = & pStructType->pHead->pTail; + while (tok != '}' && tok != EOF) { + Type* pPrimitiveType = expectPrimitiveType(); + if (pPrimitiveType) { + while (tok != ';' && tok != EOF) { + Type* pItem = acceptDeclaration(pPrimitiveType, true, false); + if (!pItem) { + break; + } + if (lookupStructMember(pStructType, pItem->id)) { + String buf; + decodeToken(buf, pItem->id, false); + error("Duplicate struct member %s", buf.getUnwrapped()); + } + Type* pStructElement = createType(TY_PARAM, pItem, NULL); + size_t alignment = pGen->alignmentOf(pItem); + if (alignment > structAlignment) { + structAlignment = alignment; + } + size_t alignmentMask = alignment - 1; + offset = (offset + alignmentMask) & ~alignmentMask; + pStructElement->length = offset; + size_t size = pGen->sizeOf(pItem); + if (isStruct) { + offset += size; + structSize = offset; + } else { + if (size >= structSize) { + structSize = size; + } + } + *pParamHolder = pStructElement; + pParamHolder = &pStructElement->pTail; + accept(','); + } + skip(';'); + } else { + // Some sort of syntax error, skip token and keep trying + next(); + } + } + if (!fail) { + pStructType->pHead->length = structSize; + pStructType->pHead->alignment = structAlignment | (isStruct << 31); + } + skip('}'); + } + if (fail) { + pStructType = NULL; + } + return pStructType; + } + + Type* lookupStructMember(Type* pStruct, tokenid_t memberId) { + for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) { + if (pStructElement->pHead->id == memberId) { + return pStructElement; + } + } + return NULL; + } + + Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) { + tokenid_t declName = 0; + bool reportFailure = false; + pType = acceptDecl2(pType, declName, nameAllowed, + nameRequired, reportFailure); + if (declName) { + // Clone the parent type so we can set a unique ID + Type* pOldType = pType; + pType = createType(pType->tag, pType->pHead, pType->pTail); + *pType = *pOldType; + pType->id = declName; + } else if (nameRequired) { + error("Expected a variable name"); + } +#if 0 + fprintf(stderr, "Parsed a declaration: "); + printType(pType); +#endif + if (reportFailure) { + return NULL; + } + return pType; + } + + Type* expectDeclaration(Type* pBaseType) { + bool nameRequired = pBaseType->tag != TY_STRUCT; + Type* pType = acceptDeclaration(pBaseType, true, nameRequired); + if (! pType) { + error("Expected a declaration"); + } + return pType; + } + + /* Used for accepting types that appear in casts */ + Type* acceptCastTypeDeclaration() { + Type* pType = acceptPrimitiveType(); + if (pType) { + pType = acceptDeclaration(pType, false, false); + } + return pType; + } + + Type* expectCastTypeDeclaration() { + Type* pType = acceptCastTypeDeclaration(); + if (! pType) { + error("Expected a declaration"); + } + return pType; + } + + Type* acceptDecl2(Type* pType, tokenid_t& declName, + bool nameAllowed, bool nameRequired, + bool& reportFailure) { + while (accept('*')) { + pType = createType(TY_POINTER, pType, NULL); + } + pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, + reportFailure); + return pType; + } + + Type* acceptDecl3(Type* pType, tokenid_t& declName, + bool nameAllowed, bool nameRequired, + bool& reportFailure) { + // direct-dcl : + // name + // (dcl) + // direct-dcl() + // direct-dcl[] + Type* pNewHead = NULL; + if (accept('(')) { + pNewHead = acceptDecl2(pNewHead, declName, nameAllowed, + nameRequired, reportFailure); + skip(')'); + } else if ((declName = acceptSymbol()) != 0) { + if (nameAllowed == false && declName) { + error("Symbol %s not allowed here", nameof(declName)); + reportFailure = true; + } + } else if (nameRequired && ! declName) { + String temp; + decodeToken(temp, tok, true); + error("Expected name. Got %s", temp.getUnwrapped()); + reportFailure = true; + } + for(;;) { + if (accept('(')) { + // Function declaration + Type* pTail = acceptArgs(nameAllowed); + pType = createType(TY_FUNC, pType, pTail); + skip(')'); + } if (accept('[')) { + if (tok != ']') { + if (tok != TOK_NUM || tokc <= 0) { + error("Expected positive integer constant"); + } else { + Type* pDecayType = createPtrType(pType); + pType = createType(TY_ARRAY, pType, pDecayType); + pType->length = tokc; + } + next(); + } + skip(']'); + } else { + break; + } + } + + if (pNewHead) { + Type* pA = pNewHead; + while (pA->pHead) { + pA = pA->pHead; + } + pA->pHead = pType; + pType = pNewHead; + } + return pType; + } + + Type* acceptArgs(bool nameAllowed) { + Type* pHead = NULL; + Type* pTail = NULL; + for(;;) { + Type* pBaseArg = acceptPrimitiveType(); + if (pBaseArg) { + Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false); + if (pArg) { + Type* pParam = createType(TY_PARAM, pArg, NULL); + if (!pHead) { + pHead = pParam; + pTail = pParam; + } else { + pTail->pTail = pParam; + pTail = pParam; + } + } + } + if (! accept(',')) { + break; + } + } + return pHead; + } + + Type* expectPrimitiveType() { + Type* pType = acceptPrimitiveType(); + if (!pType) { + String buf; + decodeToken(buf, tok, true); + error("Expected a type, got %s", buf.getUnwrapped()); + } + return pType; + } + + void checkLVal() { + if (pGen->getR0ExpressionType() != ET_LVALUE) { + error("Expected an lvalue"); + } + } + + void addGlobalSymbol(Type* pDecl) { + tokenid_t t = pDecl->id; + VariableInfo* pVI = VI(t); + if(pVI && pVI->pAddress) { + reportDuplicate(t); + } + mGlobals.add(pDecl); + } + + void reportDuplicate(tokenid_t t) { + error("Duplicate definition of %s", nameof(t)); + } + + void addLocalSymbol(Type* pDecl) { + tokenid_t t = pDecl->id; + if (mLocals.isDefinedAtCurrentLevel(t)) { + reportDuplicate(t); + } + mLocals.add(pDecl); + } + + bool checkUndeclaredStruct(Type* pBaseType) { + if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) { + String temp; + decodeToken(temp, pBaseType->structTag, false); + error("Undeclared struct %s", temp.getUnwrapped()); + return true; + } + return false; + } + + void localDeclarations(Type* pBaseType) { + intptr_t a; + + while (pBaseType) { + while (tok != ';' && tok != EOF) { + Type* pDecl = expectDeclaration(pBaseType); + if (!pDecl) { + break; + } + if (!pDecl->id) { + break; + } + if (checkUndeclaredStruct(pDecl)) { + break; + } + addLocalSymbol(pDecl); + if (pDecl->tag == TY_FUNC) { + if (tok == '{') { + error("Nested functions are not allowed. Did you forget a '}' ?"); + break; + } + // Else it's a forward declaration of a function. + } else { + int variableAddress = 0; + size_t alignment = pGen->alignmentOf(pDecl); + assert(alignment > 0); + size_t alignmentMask = ~ (alignment - 1); + size_t sizeOf = pGen->sizeOf(pDecl); + assert(sizeOf > 0); + loc = (loc + alignment - 1) & alignmentMask; + size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask; + loc = loc + alignedSize; + variableAddress = -loc; + VI(pDecl->id)->pAddress = (void*) variableAddress; + if (accept('=')) { + /* assignment */ + pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE); + pGen->pushR0(); + expr(); + pGen->forceR0RVal(); + pGen->storeR0ToTOS(); + } + } + if (tok == ',') + next(); + } + skip(';'); + pBaseType = acceptPrimitiveType(); + } + } + + bool checkSymbol() { + return checkSymbol(tok); + } + + void decodeToken(String& buffer, tokenid_t token, bool quote) { + if (token == EOF ) { + buffer.printf("EOF"); + } else if (token == TOK_NUM) { + buffer.printf("numeric constant"); + } else if (token >= 0 && token < 256) { + if (token < 32) { + buffer.printf("'\\x%02x'", token); + } else { + buffer.printf("'%c'", token); + } + } else { + if (quote) { + if (token >= TOK_KEYWORD && token < TOK_SYMBOL) { + buffer.printf("keyword \"%s\"", nameof(token)); + } else { + buffer.printf("symbol \"%s\"", nameof(token)); + } + } else { + buffer.printf("%s", nameof(token)); + } + } + } + + void printToken(tokenid_t token) { + String buffer; + decodeToken(buffer, token, true); + fprintf(stderr, "%s\n", buffer.getUnwrapped()); + } + + bool checkSymbol(tokenid_t token) { + bool result = token >= TOK_SYMBOL; + if (!result) { + String temp; + decodeToken(temp, token, true); + error("Expected symbol. Got %s", temp.getUnwrapped()); + } + return result; + } + + tokenid_t acceptSymbol() { + tokenid_t result = 0; + if (tok >= TOK_SYMBOL) { + result = tok; + next(); + } + return result; + } + + void globalDeclarations() { + mpCurrentSymbolStack = &mGlobals; + while (tok != EOF) { + Type* pBaseType = expectPrimitiveType(); + if (!pBaseType) { + break; + } + Type* pDecl = expectDeclaration(pBaseType); + if (!pDecl) { + break; + } + if (!pDecl->id) { + skip(';'); + continue; + } + + if (checkUndeclaredStruct(pDecl)) { + skip(';'); + continue; + } + + if (! isDefined(pDecl->id)) { + addGlobalSymbol(pDecl); + } + VariableInfo* name = VI(pDecl->id); + if (name && name->pAddress) { + error("Already defined global %s", nameof(pDecl->id)); + } + if (pDecl->tag < TY_FUNC) { + // it's a variable declaration + for(;;) { + if (name && !name->pAddress) { + name->pAddress = (int*) allocGlobalSpace( + pGen->alignmentOf(name->pType), + pGen->sizeOf(name->pType)); + } + if (accept('=')) { + if (tok == TOK_NUM) { + if (name) { + * (int*) name->pAddress = tokc; + } + next(); + } else { + error("Expected an integer constant"); + } + } + if (!accept(',')) { + break; + } + pDecl = expectDeclaration(pBaseType); + if (!pDecl) { + break; + } + if (! isDefined(pDecl->id)) { + addGlobalSymbol(pDecl); + } + name = VI(pDecl->id); + } + skip(';'); + } else { + // Function declaration + if (accept(';')) { + // forward declaration. + } else if (tok != '{') { + error("expected '{'"); + } else { + mpCurrentArena = &mLocalArena; + mpCurrentSymbolStack = &mLocals; + if (name) { + /* patch forward references */ + pGen->resolveForward((int) name->pForward); + /* put function address */ + name->pAddress = (void*) pCodeBuf->getPC(); + } + // Calculate stack offsets for parameters + mLocals.pushLevel(); + intptr_t a = 8; + int argCount = 0; + for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) { + Type* pArg = pP->pHead; + if (pArg->id) { + addLocalSymbol(pArg); + } + /* read param name and compute offset */ + Type* pPassingType = passingType(pArg); + size_t alignment = pGen->alignmentOf(pPassingType); + a = (a + alignment - 1) & ~ (alignment-1); + if (pArg->id) { + VI(pArg->id)->pAddress = (void*) a; + } + a = a + pGen->sizeOf(pPassingType); + argCount++; + } + rsym = loc = 0; + pReturnType = pDecl->pHead; + a = pGen->functionEntry(pDecl); + block(0, true); + pGen->gsym(rsym); + pGen->functionExit(pDecl, a, loc); + mLocals.popLevel(); + mpCurrentArena = &mGlobalArena; + mpCurrentSymbolStack = &mGlobals; + } + } + } + } + + Type* passingType(Type* pType) { + switch (pType->tag) { + case TY_CHAR: + case TY_SHORT: + return mkpInt; + default: + return pType; + } + } + + char* allocGlobalSpace(size_t alignment, size_t bytes) { + size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1); + size_t end = base + bytes; + if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) { + error("Global space exhausted"); + assert(false); + return NULL; + } + char* result = (char*) base; + glo = (char*) end; + return result; + } + + void cleanup() { + if (pGlobalBase != 0) { + free(pGlobalBase); + pGlobalBase = 0; + } + if (pGen) { + delete pGen; + pGen = 0; + } + if (pCodeBuf) { + delete pCodeBuf; + pCodeBuf = 0; + } + if (file) { + delete file; + file = 0; + } + } + + // One-time initialization, when class is constructed. + void init() { + mpSymbolLookupFn = 0; + mpSymbolLookupContext = 0; + } + + void clear() { + tok = 0; + tokc = 0; + tokl = 0; + ch = 0; + rsym = 0; + loc = 0; + glo = 0; + dptr = 0; + dch = 0; + file = 0; + pGlobalBase = 0; + pCodeBuf = 0; + pGen = 0; + mPragmaStringCount = 0; + mCompileResult = 0; + mLineNumber = 1; + mbBumpLine = false; + mbSuppressMacroExpansion = false; + } + + void setArchitecture(const char* architecture) { + delete pGen; + pGen = 0; + + delete pCodeBuf; + pCodeBuf = new CodeBuf(); + + if (architecture != NULL) { +#ifdef PROVIDE_ARM_CODEGEN + if (! pGen && strcmp(architecture, "arm") == 0) { + pGen = new ARMCodeGenerator(); + pCodeBuf = new ARMCodeBuf(pCodeBuf); + } +#endif +#ifdef PROVIDE_X86_CODEGEN + if (! pGen && strcmp(architecture, "x86") == 0) { + pGen = new X86CodeGenerator(); + } +#endif + if (!pGen ) { + error("Unknown architecture %s\n", architecture); + } + } + + if (pGen == NULL) { +#if defined(DEFAULT_ARM_CODEGEN) + pGen = new ARMCodeGenerator(); + pCodeBuf = new ARMCodeBuf(pCodeBuf); +#elif defined(DEFAULT_X86_CODEGEN) + pGen = new X86CodeGenerator(); +#endif + } + if (pGen == NULL) { + error("No code generator defined."); + } else { + pGen->setErrorSink(this); + pGen->setTypes(mkpInt); + } + } + +public: + struct args { + args() { + architecture = 0; + } + const char* architecture; + }; + + Compiler() { + init(); + clear(); + } + + ~Compiler() { + cleanup(); + } + + void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) { + mpSymbolLookupFn = pFn; + mpSymbolLookupContext = pContext; + } + + int compile(const char* text, size_t textLength) { + int result; + + mpCurrentArena = &mGlobalArena; + createPrimitiveTypes(); + cleanup(); + clear(); + mTokenTable.setArena(&mGlobalArena); + mGlobals.setArena(&mGlobalArena); + mGlobals.setTokenTable(&mTokenTable); + mLocals.setArena(&mLocalArena); + mLocals.setTokenTable(&mTokenTable); + + internKeywords(); + setArchitecture(NULL); + if (!pGen) { + return -1; + } +#ifdef PROVIDE_TRACE_CODEGEN + pGen = new TraceCodeGenerator(pGen); +#endif + pGen->setErrorSink(this); + + if (pCodeBuf) { + pCodeBuf->init(ALLOC_SIZE); + } + pGen->init(pCodeBuf); + file = new TextInputStream(text, textLength); + pGlobalBase = (char*) calloc(1, ALLOC_SIZE); + glo = pGlobalBase; + inp(); + next(); + globalDeclarations(); + checkForUndefinedForwardReferences(); + result = pGen->finishCompile(); + if (result == 0) { + if (mErrorBuf.len()) { + result = -2; + } + } + mCompileResult = result; + return result; + } + + void createPrimitiveTypes() { + mkpInt = createType(TY_INT, NULL, NULL); + mkpShort = createType(TY_SHORT, NULL, NULL); + mkpChar = createType(TY_CHAR, NULL, NULL); + mkpVoid = createType(TY_VOID, NULL, NULL); + mkpFloat = createType(TY_FLOAT, NULL, NULL); + mkpDouble = createType(TY_DOUBLE, NULL, NULL); + mkpIntFn = createType(TY_FUNC, mkpInt, NULL); + mkpIntPtr = createPtrType(mkpInt); + mkpCharPtr = createPtrType(mkpChar); + mkpFloatPtr = createPtrType(mkpFloat); + mkpDoublePtr = createPtrType(mkpDouble); + mkpPtrIntFn = createPtrType(mkpIntFn); + } + + void checkForUndefinedForwardReferences() { + mGlobals.forEach(static_ufrcFn, this); + } + + static bool static_ufrcFn(VariableInfo* value, void* context) { + Compiler* pCompiler = (Compiler*) context; + return pCompiler->undefinedForwardReferenceCheck(value); + } + + bool undefinedForwardReferenceCheck(VariableInfo* value) { + if (!value->pAddress && value->pForward) { + error("Undefined forward reference: %s", + mTokenTable[value->tok].pText); + } + return true; + } + + /* Look through the symbol table to find a symbol. + * If found, return its value. + */ + void* lookup(const char* name) { + if (mCompileResult == 0) { + tokenid_t tok = mTokenTable.intern(name, strlen(name)); + VariableInfo* pVariableInfo = VI(tok); + if (pVariableInfo) { + return pVariableInfo->pAddress; + } + } + return NULL; + } + + void getPragmas(ACCsizei* actualStringCount, + ACCsizei maxStringCount, ACCchar** strings) { + int stringCount = mPragmaStringCount; + if (actualStringCount) { + *actualStringCount = stringCount; + } + if (stringCount > maxStringCount) { + stringCount = maxStringCount; + } + if (strings) { + char* pPragmas = mPragmas.getUnwrapped(); + while (stringCount-- > 0) { + *strings++ = pPragmas; + pPragmas += strlen(pPragmas) + 1; + } + } + } + + void getProgramBinary(ACCvoid** base, ACCsizei* length) { + *base = pCodeBuf->getBase(); + *length = (ACCsizei) pCodeBuf->getSize(); + } + + char* getErrorMessage() { + return mErrorBuf.getUnwrapped(); + } +}; + +const char* Compiler::operatorChars = + "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@"; + +const char Compiler::operatorLevel[] = + {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, + 5, 5, /* ==, != */ + 9, 10, /* &&, || */ + 6, 7, 8, /* & ^ | */ + 2, 2 /* ~ ! */ + }; + +#ifdef PROVIDE_X86_CODEGEN +const int Compiler::X86CodeGenerator::operatorHelper[] = { + 0x1, // ++ + 0xff, // -- + 0xc1af0f, // * + 0xf9f79991, // / + 0xf9f79991, // % (With manual assist to swap results) + 0xc801, // + + 0xd8f7c829, // - + 0xe0d391, // << + 0xf8d391, // >> + 0xe, // <= + 0xd, // >= + 0xc, // < + 0xf, // > + 0x4, // == + 0x5, // != + 0x0, // && + 0x1, // || + 0xc821, // & + 0xc831, // ^ + 0xc809, // | + 0xd0f7, // ~ + 0x4 // ! +}; +#endif + +struct ACCscript { + ACCscript() { + text = 0; + textLength = 0; + accError = ACC_NO_ERROR; + } + + ~ACCscript() { + delete text; + } + + void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) { + compiler.registerSymbolCallback(pFn, pContext); + } + + void setError(ACCenum error) { + if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) { + accError = error; + } + } + + ACCenum getError() { + ACCenum result = accError; + accError = ACC_NO_ERROR; + return result; + } + + Compiler compiler; + char* text; + int textLength; + ACCenum accError; +}; + + +extern "C" +ACCscript* accCreateScript() { + return new ACCscript(); +} + +extern "C" +ACCenum accGetError( ACCscript* script ) { + return script->getError(); +} + +extern "C" +void accDeleteScript(ACCscript* script) { + delete script; +} + +extern "C" +void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn, + ACCvoid* pContext) { + script->registerSymbolCallback(pFn, pContext); +} + +extern "C" +void accScriptSource(ACCscript* script, + ACCsizei count, + const ACCchar ** string, + const ACCint * length) { + int totalLength = 0; + for(int i = 0; i < count; i++) { + int len = -1; + const ACCchar* s = string[i]; + if (length) { + len = length[i]; + } + if (len < 0) { + len = strlen(s); + } + totalLength += len; + } + delete script->text; + char* text = new char[totalLength + 1]; + script->text = text; + script->textLength = totalLength; + char* dest = text; + for(int i = 0; i < count; i++) { + int len = -1; + const ACCchar* s = string[i]; + if (length) { + len = length[i]; + } + if (len < 0) { + len = strlen(s); + } + memcpy(dest, s, len); + dest += len; + } + text[totalLength] = '\0'; + +#ifdef DEBUG_SAVE_INPUT_TO_FILE + LOGD("Saving input to file..."); + int counter; + char path[PATH_MAX]; + for (counter = 0; counter < 4096; counter++) { + sprintf(path, DEBUG_DUMP_PATTERN, counter); + if(access(path, F_OK) != 0) { + break; + } + } + if (counter < 4096) { + LOGD("Saving input to file %s", path); + FILE* fd = fopen(path, "w"); + if (fd) { + fwrite(text, totalLength, 1, fd); + fclose(fd); + LOGD("Saved input to file %s", path); + } else { + LOGD("Could not save. errno: %d", errno); + } + } +#endif +} + +extern "C" +void accCompileScript(ACCscript* script) { + int result = script->compiler.compile(script->text, script->textLength); + if (result) { + script->setError(ACC_INVALID_OPERATION); + } +} + +extern "C" +void accGetScriptiv(ACCscript* script, + ACCenum pname, + ACCint * params) { + switch (pname) { + case ACC_INFO_LOG_LENGTH: + *params = 0; + break; + } +} + +extern "C" +void accGetScriptInfoLog(ACCscript* script, + ACCsizei maxLength, + ACCsizei * length, + ACCchar * infoLog) { + char* message = script->compiler.getErrorMessage(); + int messageLength = strlen(message) + 1; + if (length) { + *length = messageLength; + } + if (infoLog && maxLength > 0) { + int trimmedLength = maxLength < messageLength ? + maxLength : messageLength; + memcpy(infoLog, message, trimmedLength); + infoLog[trimmedLength] = 0; + } +} + +extern "C" +void accGetScriptLabel(ACCscript* script, const ACCchar * name, + ACCvoid ** address) { + void* value = script->compiler.lookup(name); + if (value) { + *address = value; + } else { + script->setError(ACC_INVALID_VALUE); + } +} + +extern "C" +void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount, + ACCsizei maxStringCount, ACCchar** strings){ + script->compiler.getPragmas(actualStringCount, maxStringCount, strings); +} + +extern "C" +void accGetProgramBinary(ACCscript* script, + ACCvoid** base, ACCsizei* length) { + script->compiler.getProgramBinary(base, length); +} + + +} // namespace acc + diff --git a/libacc/tests/.gitignore b/libacc/tests/.gitignore new file mode 100644 index 00000000000..a26b298632c --- /dev/null +++ b/libacc/tests/.gitignore @@ -0,0 +1,2 @@ +test-acc +*.out diff --git a/libacc/tests/Android.mk b/libacc/tests/Android.mk new file mode 100644 index 00000000000..e9fbe03199d --- /dev/null +++ b/libacc/tests/Android.mk @@ -0,0 +1,66 @@ +LOCAL_PATH:= $(call my-dir) + +# Executable for host +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE:= acc + +LOCAL_SRC_FILES:= \ + main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libacc + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_HOST_EXECUTABLE) + +# Executable for target +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE:= acc + +LOCAL_SRC_FILES:= \ + main.cpp \ + disassem.cpp + +LOCAL_SHARED_LIBRARIES := \ + libacc + +LOCAL_CFLAGS := -O0 -g + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) + +# Runtime tests for host +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE:= accRuntimeTest + +LOCAL_SRC_FILES:= \ + runtimeTest.cpp + +LOCAL_SHARED_LIBRARIES := \ + libacc + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_HOST_EXECUTABLE) + +# Runtime tests for target +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE:= accRuntimeTest + +LOCAL_SRC_FILES:= \ + runtimeTest.cpp + +LOCAL_SHARED_LIBRARIES := \ + libacc + +LOCAL_CFLAGS := -O0 -g + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/libacc/tests/accarm b/libacc/tests/accarm new file mode 100755 index 00000000000..6b1bf663f6c --- /dev/null +++ b/libacc/tests/accarm @@ -0,0 +1,69 @@ +#!/usr/bin/python +# +# Run a test on the ARM version of acc. + +import unittest +import subprocess +import os +import sys + +def compile(args): + proc = subprocess.Popen(["acc"] + args, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + result = proc.communicate() + return result + +def runCmd(args): + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = proc.communicate() + return result[0].strip() + +def uname(): + return runCmd(["uname"]) + +def unameM(): + return runCmd(["uname", "-m"]) + +def which(item): + return runCmd(["which", item]) + +def adb(args): + return runCmd(["adb"] + args) + +def setupArm(file): + print "Setting up arm" + adb(["remount"]) + adb(["shell", "rm", "/system/bin/acc"]) + adb(["shell", "mkdir", "/system/bin/accdata"]) + adb(["shell", "mkdir", "/system/bin/accdata/data"]) + + remoteFileName = os.path.join("/system/bin/accdata", file) + adb(["push", file, remoteFileName]) + + # Copy over compiler + adb(["sync"]) + return remoteFileName + +def compileArm(args): + remoteArgs = [] + fileName = "" + for arg in sys.argv[1:]: + if arg.startswith('-'): + remoteArgs.append(arg) + else: + fileName = arg + + remoteFileName = setupArm(fileName) + remoteArgs.append(remoteFileName) + remoteCmdLine = ["adb", "shell", "/system/bin/acc"] + remoteArgs + proc = subprocess.Popen(remoteCmdLine, stdout=subprocess.PIPE) + result = proc.communicate() + return result[0].replace("\r","") + + +def main(): + print compileArm(sys.argv[1:]) + +if __name__ == '__main__': + main() + + diff --git a/libacc/tests/armreg.h b/libacc/tests/armreg.h new file mode 100644 index 00000000000..fde81ba8976 --- /dev/null +++ b/libacc/tests/armreg.h @@ -0,0 +1,300 @@ +/* $NetBSD: armreg.h,v 1.28 2003/10/31 16:30:15 scw Exp $ */ + +/*- + * Copyright (c) 1998, 2001 Ben Harris + * Copyright (c) 1994-1996 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * This code is derived from software written for Brini by Mark Brinicombe + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Brini. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/armreg.h,v 1.3 2005/11/21 19:06:25 cognet Exp $ + */ + +#ifndef MACHINE_ARMREG_H +#define MACHINE_ARMREG_H +#define INSN_SIZE 4 +#define INSN_COND_MASK 0xf0000000 /* Condition mask */ +#define PSR_MODE 0x0000001f /* mode mask */ +#define PSR_USR26_MODE 0x00000000 +#define PSR_FIQ26_MODE 0x00000001 +#define PSR_IRQ26_MODE 0x00000002 +#define PSR_SVC26_MODE 0x00000003 +#define PSR_USR32_MODE 0x00000010 +#define PSR_FIQ32_MODE 0x00000011 +#define PSR_IRQ32_MODE 0x00000012 +#define PSR_SVC32_MODE 0x00000013 +#define PSR_ABT32_MODE 0x00000017 +#define PSR_UND32_MODE 0x0000001b +#define PSR_SYS32_MODE 0x0000001f +#define PSR_32_MODE 0x00000010 +#define PSR_FLAGS 0xf0000000 /* flags */ + +#define PSR_C_bit (1 << 29) /* carry */ + +/* The high-order byte is always the implementor */ +#define CPU_ID_IMPLEMENTOR_MASK 0xff000000 +#define CPU_ID_ARM_LTD 0x41000000 /* 'A' */ +#define CPU_ID_DEC 0x44000000 /* 'D' */ +#define CPU_ID_INTEL 0x69000000 /* 'i' */ +#define CPU_ID_TI 0x54000000 /* 'T' */ + +/* How to decide what format the CPUID is in. */ +#define CPU_ID_ISOLD(x) (((x) & 0x0000f000) == 0x00000000) +#define CPU_ID_IS7(x) (((x) & 0x0000f000) == 0x00007000) +#define CPU_ID_ISNEW(x) (!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x)) + +/* On ARM3 and ARM6, this byte holds the foundry ID. */ +#define CPU_ID_FOUNDRY_MASK 0x00ff0000 +#define CPU_ID_FOUNDRY_VLSI 0x00560000 + +/* On ARM7 it holds the architecture and variant (sub-model) */ +#define CPU_ID_7ARCH_MASK 0x00800000 +#define CPU_ID_7ARCH_V3 0x00000000 +#define CPU_ID_7ARCH_V4T 0x00800000 +#define CPU_ID_7VARIANT_MASK 0x007f0000 + +/* On more recent ARMs, it does the same, but in a different format */ +#define CPU_ID_ARCH_MASK 0x000f0000 +#define CPU_ID_ARCH_V3 0x00000000 +#define CPU_ID_ARCH_V4 0x00010000 +#define CPU_ID_ARCH_V4T 0x00020000 +#define CPU_ID_ARCH_V5 0x00030000 +#define CPU_ID_ARCH_V5T 0x00040000 +#define CPU_ID_ARCH_V5TE 0x00050000 +#define CPU_ID_VARIANT_MASK 0x00f00000 + +/* Next three nybbles are part number */ +#define CPU_ID_PARTNO_MASK 0x0000fff0 + +/* Intel XScale has sub fields in part number */ +#define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */ +#define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */ +#define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */ + +/* And finally, the revision number. */ +#define CPU_ID_REVISION_MASK 0x0000000f + +/* Individual CPUs are probably best IDed by everything but the revision. */ +#define CPU_ID_CPU_MASK 0xfffffff0 + +/* Fake CPU IDs for ARMs without CP15 */ +#define CPU_ID_ARM2 0x41560200 +#define CPU_ID_ARM250 0x41560250 + +/* Pre-ARM7 CPUs -- [15:12] == 0 */ +#define CPU_ID_ARM3 0x41560300 +#define CPU_ID_ARM600 0x41560600 +#define CPU_ID_ARM610 0x41560610 +#define CPU_ID_ARM620 0x41560620 + +/* ARM7 CPUs -- [15:12] == 7 */ +#define CPU_ID_ARM700 0x41007000 /* XXX This is a guess. */ +#define CPU_ID_ARM710 0x41007100 +#define CPU_ID_ARM7500 0x41027100 /* XXX This is a guess. */ +#define CPU_ID_ARM710A 0x41047100 /* inc ARM7100 */ +#define CPU_ID_ARM7500FE 0x41077100 +#define CPU_ID_ARM710T 0x41807100 +#define CPU_ID_ARM720T 0x41807200 +#define CPU_ID_ARM740T8K 0x41807400 /* XXX no MMU, 8KB cache */ +#define CPU_ID_ARM740T4K 0x41817400 /* XXX no MMU, 4KB cache */ + +/* Post-ARM7 CPUs */ +#define CPU_ID_ARM810 0x41018100 +#define CPU_ID_ARM920T 0x41129200 +#define CPU_ID_ARM920T_ALT 0x41009200 +#define CPU_ID_ARM922T 0x41029220 +#define CPU_ID_ARM940T 0x41029400 /* XXX no MMU */ +#define CPU_ID_ARM946ES 0x41049460 /* XXX no MMU */ +#define CPU_ID_ARM966ES 0x41049660 /* XXX no MMU */ +#define CPU_ID_ARM966ESR1 0x41059660 /* XXX no MMU */ +#define CPU_ID_ARM1020E 0x4115a200 /* (AKA arm10 rev 1) */ +#define CPU_ID_ARM1022ES 0x4105a220 +#define CPU_ID_SA110 0x4401a100 +#define CPU_ID_SA1100 0x4401a110 +#define CPU_ID_TI925T 0x54029250 +#define CPU_ID_SA1110 0x6901b110 +#define CPU_ID_IXP1200 0x6901c120 +#define CPU_ID_80200 0x69052000 +#define CPU_ID_PXA250 0x69052100 /* sans core revision */ +#define CPU_ID_PXA210 0x69052120 +#define CPU_ID_PXA250A 0x69052100 /* 1st version Core */ +#define CPU_ID_PXA210A 0x69052120 /* 1st version Core */ +#define CPU_ID_PXA250B 0x69052900 /* 3rd version Core */ +#define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */ +#define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */ +#define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */ +#define CPU_ID_80321_400 0x69052420 +#define CPU_ID_80321_600 0x69052430 +#define CPU_ID_80321_400_B0 0x69052c20 +#define CPU_ID_80321_600_B0 0x69052c30 +#define CPU_ID_IXP425_533 0x690541c0 +#define CPU_ID_IXP425_400 0x690541d0 +#define CPU_ID_IXP425_266 0x690541f0 + +/* ARM3-specific coprocessor 15 registers */ +#define ARM3_CP15_FLUSH 1 +#define ARM3_CP15_CONTROL 2 +#define ARM3_CP15_CACHEABLE 3 +#define ARM3_CP15_UPDATEABLE 4 +#define ARM3_CP15_DISRUPTIVE 5 + +/* ARM3 Control register bits */ +#define ARM3_CTL_CACHE_ON 0x00000001 +#define ARM3_CTL_SHARED 0x00000002 +#define ARM3_CTL_MONITOR 0x00000004 + +/* + * Post-ARM3 CP15 registers: + * + * 1 Control register + * + * 2 Translation Table Base + * + * 3 Domain Access Control + * + * 4 Reserved + * + * 5 Fault Status + * + * 6 Fault Address + * + * 7 Cache/write-buffer Control + * + * 8 TLB Control + * + * 9 Cache Lockdown + * + * 10 TLB Lockdown + * + * 11 Reserved + * + * 12 Reserved + * + * 13 Process ID (for FCSE) + * + * 14 Reserved + * + * 15 Implementation Dependent + */ + +/* Some of the definitions below need cleaning up for V3/V4 architectures */ + +/* CPU control register (CP15 register 1) */ +#define CPU_CONTROL_MMU_ENABLE 0x00000001 /* M: MMU/Protection unit enable */ +#define CPU_CONTROL_AFLT_ENABLE 0x00000002 /* A: Alignment fault enable */ +#define CPU_CONTROL_DC_ENABLE 0x00000004 /* C: IDC/DC enable */ +#define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */ +#define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */ +#define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */ +#define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */ +#define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */ +#define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */ +#define CPU_CONTROL_ROM_ENABLE 0x00000200 /* R: ROM protection bit */ +#define CPU_CONTROL_CPCLK 0x00000400 /* F: Implementation defined */ +#define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */ +#define CPU_CONTROL_IC_ENABLE 0x00001000 /* I: IC enable */ +#define CPU_CONTROL_VECRELOC 0x00002000 /* V: Vector relocation */ +#define CPU_CONTROL_ROUNDROBIN 0x00004000 /* RR: Predictable replacement */ +#define CPU_CONTROL_V4COMPAT 0x00008000 /* L4: ARMv4 compat LDR R15 etc */ + +#define CPU_CONTROL_IDC_ENABLE CPU_CONTROL_DC_ENABLE + +/* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */ +#define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */ +#define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */ +#define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */ +#define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */ +#define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */ +#define XSCALE_AUXCTL_MD_MASK 0x00000030 + +/* Cache type register definitions */ +#define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */ +#define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */ +#define CPU_CT_S (1U << 24) /* split cache */ +#define CPU_CT_CTYPE(x) (((x) >> 25) & 0xf) /* cache type */ + +#define CPU_CT_CTYPE_WT 0 /* write-through */ +#define CPU_CT_CTYPE_WB1 1 /* write-back, clean w/ read */ +#define CPU_CT_CTYPE_WB2 2 /* w/b, clean w/ cp15,7 */ +#define CPU_CT_CTYPE_WB6 6 /* w/b, cp15,7, lockdown fmt A */ +#define CPU_CT_CTYPE_WB7 7 /* w/b, cp15,7, lockdown fmt B */ + +#define CPU_CT_xSIZE_LEN(x) ((x) & 0x3) /* line size */ +#define CPU_CT_xSIZE_M (1U << 2) /* multiplier */ +#define CPU_CT_xSIZE_ASSOC(x) (((x) >> 3) & 0x7) /* associativity */ +#define CPU_CT_xSIZE_SIZE(x) (((x) >> 6) & 0x7) /* size */ + +/* Fault status register definitions */ + +#define FAULT_TYPE_MASK 0x0f +#define FAULT_USER 0x10 + +#define FAULT_WRTBUF_0 0x00 /* Vector Exception */ +#define FAULT_WRTBUF_1 0x02 /* Terminal Exception */ +#define FAULT_BUSERR_0 0x04 /* External Abort on Linefetch -- Section */ +#define FAULT_BUSERR_1 0x06 /* External Abort on Linefetch -- Page */ +#define FAULT_BUSERR_2 0x08 /* External Abort on Non-linefetch -- Section */ +#define FAULT_BUSERR_3 0x0a /* External Abort on Non-linefetch -- Page */ +#define FAULT_BUSTRNL1 0x0c /* External abort on Translation -- Level 1 */ +#define FAULT_BUSTRNL2 0x0e /* External abort on Translation -- Level 2 */ +#define FAULT_ALIGN_0 0x01 /* Alignment */ +#define FAULT_ALIGN_1 0x03 /* Alignment */ +#define FAULT_TRANS_S 0x05 /* Translation -- Section */ +#define FAULT_TRANS_P 0x07 /* Translation -- Page */ +#define FAULT_DOMAIN_S 0x09 /* Domain -- Section */ +#define FAULT_DOMAIN_P 0x0b /* Domain -- Page */ +#define FAULT_PERM_S 0x0d /* Permission -- Section */ +#define FAULT_PERM_P 0x0f /* Permission -- Page */ + +#define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */ + +/* + * Address of the vector page, low and high versions. + */ +#define ARM_VECTORS_LOW 0x00000000U +#define ARM_VECTORS_HIGH 0xffff0000U + +/* + * ARM Instructions + * + * 3 3 2 2 2 + * 1 0 9 8 7 0 + * +-------+-------------------------------------------------------+ + * | cond | instruction dependant | + * |c c c c| | + * +-------+-------------------------------------------------------+ + */ + +#define INSN_SIZE 4 /* Always 4 bytes */ +#define INSN_COND_MASK 0xf0000000 /* Condition mask */ +#define INSN_COND_AL 0xe0000000 /* Always condition */ + +#endif /* !MACHINE_ARMREG_H */ diff --git a/libacc/tests/data/addressOf.c b/libacc/tests/data/addressOf.c new file mode 100644 index 00000000000..e7acde53df1 --- /dev/null +++ b/libacc/tests/data/addressOf.c @@ -0,0 +1,31 @@ +void testStruct() { + struct str { + float x; + float y; + }; + + struct str base; + int index = 0; + + base.x = 10.0; + struct str *s = &base; + + float *v = &(*s).x; + float *v2 = &s[index].x; + printf("testStruct: %g %g %g\n",base.x, *v, *v2); +} + +void testArray() { + int a[2]; + a[0] = 1; + a[1] = 2; + int* p = &a[0]; + int* p2 = a; + printf("testArray: %d %d %d\n", a[0], *p, *p2); +} + +int main() { + testStruct(); + testArray(); + return 0; +} diff --git a/libacc/tests/data/array.c b/libacc/tests/data/array.c new file mode 100644 index 00000000000..ca4a7283c1d --- /dev/null +++ b/libacc/tests/data/array.c @@ -0,0 +1,107 @@ +// Array allocation tests + +void testLocalInt() +{ + int a[3]; + a[0] = 1; + a[1] = 2; + a[2] = a[0] + a[1]; + printf("localInt: %d\n", a[2]); +} + +char a[3]; +double d[3]; + +void testGlobalChar() +{ + a[0] = 1; + a[1] = 2; + a[2] = a[0] + a[1]; + printf("globalChar: %d\n", a[2]); +} + +void testGlobalDouble() +{ + d[0] = 1; + d[1] = 2; + d[2] = d[0] + d[1]; + printf("globalDouble: %g\n", d[2]); +} + +void testLocalDouble() +{ + double d[3]; + float m[12]; + m[0] = 1.0f; + m[1] = 2.0f; + d[0] = 1.0; + d[1] = 2.0; + d[2] = d[0] + d[1]; + m[2] = m[0] + m[1]; + printf("localDouble: %g %g\n", d[2], m[2]); +} + +void vectorAdd(int* a, int* b, float* c, int len) { + int i; + for(i = 0; i < len; i++) { + c[i] = a[i] + b[i]; + } +} + +void testArgs() { + int a[3], b[3]; + float c[3]; + int i; + int len = 3; + for(i = 0; i < len; i++) { + a[i] = i; + b[i] = i; + c[i] = 0; + } + vectorAdd(a,b,c, len); + printf("testArgs:"); + for(i = 0; i < len; i++) { + printf(" %g", c[i]); + } + printf("\n"); +} + +void testDecay() { + char c[4]; + c[0] = 'H'; + c[1] = 'i'; + c[2] = '!'; + c[3] = 0; + printf("testDecay: %s\n", c); +} + +void test2D() { + char c[10][20]; + int x; + int y; + printf("test2D:\n"); + for(y = 0; y < 10; y++) { + for(x = 0; x < 20; x++) { + c[y][x] = 'a' + (15 & (y * 19 + x)); + } + } + for(y = 0; y < 10; y++) { + for(x = 0; x < 20; x++) { + printf("%c", c[y][x]); + } + printf("\n"); + } + +} + +int main() +{ + testLocalInt(); + testLocalDouble(); + testGlobalChar(); + testGlobalDouble(); + testArgs(); + testDecay(); + test2D(); + return 0; +} diff --git a/libacc/tests/data/assignment.c b/libacc/tests/data/assignment.c new file mode 100644 index 00000000000..4fc7801d0a6 --- /dev/null +++ b/libacc/tests/data/assignment.c @@ -0,0 +1,9 @@ +int main() { + int a = 0; + int b = 1; + a = b = 2; // Test that "b = 2" generates an rvalue. + if (a = 7) { // Test that a = 7 generates an rvalue. + b = 3; + } + return a; +} diff --git a/libacc/tests/data/assignmentop.c b/libacc/tests/data/assignmentop.c new file mode 100644 index 00000000000..649edf9b6f3 --- /dev/null +++ b/libacc/tests/data/assignmentop.c @@ -0,0 +1,62 @@ +// Test assignment operations + +void testAssignment() { + int a = 2; + a *= 5; + printf("2 *= 5 %d\n", a); + a = 20; + a /= 5; + printf("20 /= 5 %d\n", a); + a = 17; + a %= 5; + printf("17 %%= 5 %d\n", a); + a = 17; + a += 5; + printf("17 += 5 %d\n", a); + a = 17; + a-=5; + printf("17 -= 5 %d\n", a); + a = 17; + a<<=1; + printf("17<<= 1 %d\n", a); + a = 17; + a>>=1; + printf("17>>= 1 %d\n", a); + a = 17; + a&=1; + printf("17&= 1 %d\n", a); + a = 17; + a^=1; + printf("17^= 1 %d\n", a); + a = 16; + a^=1; + printf("16|= 1 %d\n", a); +} + +int a; + +int* f() { + printf("f()\n"); + return &a; +} + +void testEval() { + a = 0; + printf("*f() = *f() + 10;\n"); + *f() = *f() + 10; + printf("a = %d\n", a); +} + +void testOpEval() { + a = 0; + printf("*f() += 10;\n"); + *f() += 10; + printf("a = %d\n", a); +} + +int main() { + testAssignment(); + testEval(); + testOpEval(); + return 0; +} diff --git a/libacc/tests/data/b2071670.c b/libacc/tests/data/b2071670.c new file mode 100644 index 00000000000..311bc4f49c2 --- /dev/null +++ b/libacc/tests/data/b2071670.c @@ -0,0 +1,9 @@ +// See http://b/2071670 + +int main() { + float f = 10.0f; + float* floatPointer = &f; + // The following line used to incorrectly error: "Incompatible pointer or array types" + int* buffer = (int*) floatPointer; + return *buffer; +} diff --git a/libacc/tests/data/bellard.otccex.c b/libacc/tests/data/bellard.otccex.c new file mode 100644 index 00000000000..e8f098914da --- /dev/null +++ b/libacc/tests/data/bellard.otccex.c @@ -0,0 +1,126 @@ +/* #!/usr/local/bin/otcc */ +/* + * Sample OTCC C example. You can uncomment the first line and install + * otcc in /usr/local/bin to make otcc scripts ! + */ + +/* Any preprocessor directive except #define are ignored. We put this + include so that a standard C compiler can compile this code too. */ +#include + +/* defines are handled, but macro arguments cannot be given. No + recursive defines are tolerated */ +#define DEFAULT_BASE 10 + +/* + * Only old style K&R prototypes are parsed. Only int arguments are + * allowed (implicit types). + * + * By benchmarking the execution time of this function (for example + * for fib(35)), you'll notice that OTCC is quite fast because it + * generates native i386 machine code. + */ +fib(n) +{ + if (n <= 2) + return 1; + else + return fib(n-1) + fib(n-2); +} + +/* Identifiers are parsed the same way as C: begins with letter or + '_', and then letters, '_' or digits */ +fact(n) +{ + /* local variables can be declared. Only 'int' type is supported */ + int i, r; + r = 1; + /* 'while' and 'for' loops are supported */ + for(i=2;i<=n;i++) + r = r * i; + return r; +} + +/* Well, we could use printf, but it would be too easy */ +print_num(n, b) +{ + int tab, p, c; + /* Numbers can be entered in decimal, hexadecimal ('0x' prefix) and + octal ('0' prefix) */ + /* more complex programs use malloc */ + tab = malloc(0x100); + p = tab; + while (1) { + c = n % b; + /* Character constants can be used */ + if (c >= 10) + c = c + 'a' - 10; + else + c = c + '0'; + *(char *)p = c; + p++; + n = n / b; + /* 'break' is supported */ + if (n == 0) + break; + } + while (p != tab) { + p--; + printf("%c", *(char *)p); + } + free(tab); +} + +/* 'main' takes standard 'argc' and 'argv' parameters */ +main(argc, argv) +{ + /* no local name space is supported, but local variables ARE + supported. As long as you do not use a globally defined + variable name as local variable (which is a bad habbit), you + won't have any problem */ + int s, n, f, base; + + /* && and || operator have the same semantics as C (left to right + evaluation and early exit) */ + if (argc != 2 && argc != 3) { + /* '*' operator is supported with explicit casting to 'int *', + 'char *' or 'int (*)()' (function pointer). Of course, 'int' + are supposed to be used as pointers too. */ + s = *(int *)argv; + help(s); + return 1; + } + /* Any libc function can be used because OTCC uses dynamic linking */ + n = atoi(*(int *)(argv + 4)); + base = DEFAULT_BASE; + if (argc >= 3) { + base = atoi(*(int *)(argv + 8)); + if (base < 2 || base > 36) { + /* external variables can be used too (here: 'stderr') */ + fprintf(stderr, "Invalid base\n"); + return 1; + } + } + printf("fib(%d) = ", n); + print_num(fib(n), base); + printf("\n"); + + printf("fact(%d) = ", n); + if (n > 12) { + printf("Overflow"); + } else { + /* why not using a function pointer ? */ + f = &fact; + print_num((*(int (*)())f)(n), base); + } + printf("\n"); + return 0; +} + +/* functions can be used before being defined */ +help(name) +{ + printf("usage: %s n [base]\n", name); + printf("Compute fib(n) and fact(n) and output the result in base 'base'\n"); +} + diff --git a/libacc/tests/data/brackets.c b/libacc/tests/data/brackets.c new file mode 100644 index 00000000000..bab88a2fdc6 --- /dev/null +++ b/libacc/tests/data/brackets.c @@ -0,0 +1,61 @@ +void testBrackets(int* ar, int len) { + int i; + int errors = 0; + for (i = 0; i < len; i++) { + ar[i] = i; + } + for (i = 0; i < len; i++) { + if (ar[i] != i) { + printf("error: [%d] %d != %d\n", i, ar[i], i); + errors++; + } + } + printf("Errors: %d\n", errors); +} + +void testBrackets2D(int** ar2D, int lenX, int lenY) { + int x, y; + int errors = 0; + for (x = 0; x < lenX; x++) { + for (y = 0; y < lenY; y++) { + ar2D[x][y] = x * lenY + y; + } + } + for (x = 0; x < lenX; x++) { + for (y = 0; y < lenY; y++) { + int expected = x * lenY + y; + int val = ar2D[x][y]; + if (val != expected) { + printf("error: [%d][%d] %d != %d\n", x, y, val, expected); + errors++; + } + } + } + printf("2D Errors: %d\n", errors); +} + +void testHeap() { + int* ar = (int*) malloc(100); + testBrackets(ar, 25); + free(ar); +} + +void testHeap2D() { + int lenX = 10; + int lenY = 5; + int* ar = (int*) malloc(lenX * lenY * 4); + int** ar2D = (int**) malloc(lenX * 4); + int i; + for(i = 0; i < lenX; i++) { + ar2D[i] = ar + lenY * i; + } + testBrackets2D(ar2D, lenX, lenY); + free(ar); + free(ar2D); +} + +int main() { + testHeap(); + testHeap2D(); + return 0; +} diff --git a/libacc/tests/data/casts.c b/libacc/tests/data/casts.c new file mode 100644 index 00000000000..d3a49b4cf3f --- /dev/null +++ b/libacc/tests/data/casts.c @@ -0,0 +1,85 @@ +void test1() { + int a = 3; + int* pb = &a; + int c = *pb; + printf("Reading from a pointer: %d %d\n", a, c); + *pb = 4; + printf("Writing to a pointer: %d\n", a); + printf("Testing casts: %d %g %g %d\n", 3, (float) 3, 4.5, (int) 4.5); +} + +void test2() { + int x = 4; + int px = &x; + // int z = * px; // An error, expected a pointer type + int y = * (int*) px; + printf("Testing reading (int*): %d\n", y); +} + +void test3() { + int px = (int) malloc(120); + * (int*) px = 8; + * (int*) (px + 4) = 9; + printf("Testing writing (int*): %d %d\n", * (int*) px, * (int*) (px + 4)); + free((void*) px); +} + +void test4() { + int x = 0x12345678; + int px = &x; + int a = * (char*) px; + int b = * (char*) (px + 1); + int c = * (char*) (px + 2); + int d = * (char*) (px + 3); + printf("Testing reading (char*): 0x%02x 0x%02x 0x%02x 0x%02x\n", a, b, c, d); +} + +void test5() { + int x = 0xFFFFFFFF; + int px = &x; + * (char*) px = 0x21; + * (char*) (px + 1) = 0x43; + * (char*) (px + 2) = 0x65; + * (char*) (px + 3) = 0x87; + printf("Testing writing (char*): 0x%08x\n", x); +} + +int f(int b) { + printf("f(%d)\n", b); + return 7 * b; +} + +void test6() { + int fp = &f; + int x = (*(int(*)()) fp)(10); + printf("Function pointer result: %d\n", x); +} + +void test7() { + int px = (int) malloc(120); + * (float*) px = 8.8f; + * (float*) (px + 4) = 9.9f; + printf("Testing read/write (float*): %g %g\n", * (float*) px, * (float*) (px + 4)); + free((void*) px); +} + +void test8() { + int px = (int) malloc(120); + * (double*) px = 8.8; + * (double*) (px + 8) = 9.9; + printf("Testing read/write (double*): %g %g\n", * (double*) px, * (double*) (px + 8)); + free((void*) px); +} + + +int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + return 0; +} diff --git a/libacc/tests/data/char.c b/libacc/tests/data/char.c new file mode 100644 index 00000000000..8c63ba28550 --- /dev/null +++ b/libacc/tests/data/char.c @@ -0,0 +1,13 @@ +char ga; +char gb; + +int main() { + char a = 'c'; + char b = a * 3; + printf("a = %d, b = %d\n", a, b); + ga = 'd'; + gb = ga * 3; + printf("ga = %d, gb = %d\n", ga, gb); + return 0; +} + diff --git a/libacc/tests/data/comma.c b/libacc/tests/data/comma.c new file mode 100644 index 00000000000..496944ca8ff --- /dev/null +++ b/libacc/tests/data/comma.c @@ -0,0 +1,35 @@ +int testReturn() { + return 10, 20, 30; +} + +int testArg(int a) { + return a; +} + +void testComma() { + int a; + 0, a = 10,20; + printf("statement: %d\n", a); + a = 1; + if (a = 0, 1) { + printf("if: a = %d\n", a); + } + int b = 0; + a = 10; + while(b++,a--) {} + printf("while: b = %d\n", b); + b = 0; + for(b++,a = 0;b++, a < 10; b++, a++) {} + printf("for: b = %d\n", b); + b = testReturn(); + printf("return: %d\n", b); + b = testArg((a,12)); + printf("arg: %d\n", b); +} + + + +int main() { + testComma(); + return 0; +} diff --git a/libacc/tests/data/constants.c b/libacc/tests/data/constants.c new file mode 100644 index 00000000000..230109a4ebf --- /dev/null +++ b/libacc/tests/data/constants.c @@ -0,0 +1,30 @@ +#define FOO 0x10 + +int main() { + printf("0 = %d\n", 0); + printf("010 = %d\n", 010); + printf("0x10 = %d\n", FOO); + printf("'\\a' = %d\n", '\a'); + printf("'\\b' = %d\n", '\b'); + printf("'\\f' = %d\n", '\f'); + printf("'\\n' = %d\n", '\n'); + printf("'\\r' = %d\n", '\r'); + printf("'\\t' = %d\n", '\t'); + printf("'\\v' = %d\n", '\v'); + // Undefined + // printf("'\\z' = %d\n", '\z'); + printf("'\\\\' = %d\n", '\\'); + printf("'\\'' = %d\n", '\''); + printf("'\\\"' = %d\n", '\"'); + printf("'\\?' = %d\n", '\?'); + printf("'\\0' = %d\n", '\0'); + printf("'\\1' = %d\n", '\1'); + printf("'\\12' = %d\n", '\12'); + printf("'\\123' = %d\n", '\123'); + printf("'\\x0' = %d\n", '\x0'); + printf("'\\x1' = %d\n", '\x1'); + printf("'\\x12' = %d\n", '\x12'); + printf("'\\x123' = %d\n", '\x123'); + printf("'\\x1f' = %d\n", '\x1f'); + printf("'\\x1F' = %d\n", '\x1F'); +} diff --git a/libacc/tests/data/defines.c b/libacc/tests/data/defines.c new file mode 100644 index 00000000000..6cb6f7ebf67 --- /dev/null +++ b/libacc/tests/data/defines.c @@ -0,0 +1,9 @@ +// Simple tests of the C preprocessor + +#define A 1 +#define A (4 / 2) +#define B 1 // This is a comment. With a / in it. + +int main() { + return A + B; +} diff --git a/libacc/tests/data/double.c b/libacc/tests/data/double.c new file mode 100644 index 00000000000..5bc20a399a4 --- /dev/null +++ b/libacc/tests/data/double.c @@ -0,0 +1,7 @@ +double atof(char *nptr); + +int main() { + printf("Value = %g\n", atof("10.42")); + return 0; +} + diff --git a/libacc/tests/data/error.c b/libacc/tests/data/error.c new file mode 100644 index 00000000000..2e08dcc2119 --- /dev/null +++ b/libacc/tests/data/error.c @@ -0,0 +1,2 @@ +void foo; + diff --git a/libacc/tests/data/expr-ansi.c b/libacc/tests/data/expr-ansi.c new file mode 100644 index 00000000000..d463659bda6 --- /dev/null +++ b/libacc/tests/data/expr-ansi.c @@ -0,0 +1,60 @@ +/* Test operators */ + +void testInc() { int a, b; a = 3; b = a++; printf("3++ = %d %d\n", b, a); } +void testDec() { int a, b; a = 3; b = a--; printf("3-- = %d %d\n", b, a); } +void testTimes(){ printf("%d * %d = %d\n", 10, 4, 10 * 4); } +void testDiv(){ printf("%d / %d = %d\n", 11, 4, 11 / 4); } +void testMod(){ printf("%d %% %d = %d\n", 11, 4, 11 % 4); } +void testPlus(){ printf("%d + %d = %d\n", 10, 4, 10 + 4); } +void testMinus(){ printf("%d - %d = %d\n", 10, 4, 10 - 4); } +void testShiftLeft(){ printf("%d << %d = %d\n", 10, 4, 10 << 4); } +void testShiftRight(){ printf("%d >> %d = %d\n", 100, 4, 100 >> 4); } +void testLess(){ printf("%d < %d = %d\n", 10, 4, 10 < 4); } +void testLesEqual(){ printf("%d <= %d = %d\n", 10, 4, 10 <= 4); } +void testGreater(){ printf("%d > %d = %d\n", 10, 4, 10 > 4); } +void testGreaterEqual(){ printf("%d >= %d = %d\n", 10, 4, 10 >= 4); } +void testEqualTo(){ printf("%d == %d = %d\n", 10, 4, 10 == 4); } +void testNotEqualTo(){ printf("%d != %d = %d\n", 10, 4, 10 != 4); } +void testBitAnd(){ printf("%d & %d = %d\n", 10, 7, 10 & 7); } +void testBitXor(){ printf("%d ^ %d = %d\n", 10, 7, 10 ^ 7); } +void testBitOr(){ printf("%d | %d = %d\n", 10, 4, 10 | 4); } +void testAssignment(){ int a, b; a = 3; b = a; printf("b == %d\n", b); } +void testLogicalAnd(){ printf("%d && %d = %d\n", 10, 4, 10 && 4); } +void testLogicalOr(){ printf("%d || %d = %d\n", 10, 4, 10 || 4); } +void testAddressOf(){ int a; printf("&a is %d\n", &a); } +void testPointerIndirection(){ int a, b; a = &b; b = 17; printf("*%d = %d =?= %d\n", a, * (int*) a, b); } +void testNegation(){ printf("-%d = %d\n", 10, -10); } +void testUnaryPlus(){ printf("+%d = %d\n", 10, +10); } +void testUnaryNot(){ printf("!%d = %d\n", 10, !10); } +void testBitNot(){ printf("~%d = %d\n", 10, ~10); } + +int main(int a, char** b) { + testInc(); + testDec(); + testTimes(); + testDiv(); + testMod(); + testPlus(); + testMinus(); + testShiftLeft(); + testShiftRight(); + testLess(); + testLesEqual(); + testGreater(); + testGreaterEqual(); + testEqualTo(); + testNotEqualTo(); + testBitAnd(); + testBinXor(); + testBitOr(); + testAssignment(); + testLogicalAnd(); + testLogicalOr(); + testAddressOf(); + testPointerIndirection(); + testNegation(); + testUnaryPlus(); + testUnaryNot(); + testBitNot(); + return 0; +} diff --git a/libacc/tests/data/expr.c b/libacc/tests/data/expr.c new file mode 100644 index 00000000000..4f2d2e78f4b --- /dev/null +++ b/libacc/tests/data/expr.c @@ -0,0 +1,60 @@ +/* Test operators */ + +testInc() { int a, b; a = 3; b = a++; printf("3++ = %d %d\n", b, a); } +testDec() { int a, b; a = 3; b = a--; printf("3-- = %d %d\n", b, a); } +testTimes(){ printf("%d * %d = %d\n", 10, 4, 10 * 4); } +testDiv(){ printf("%d / %d = %d\n", 11, 4, 11 / 4); } +testMod(){ printf("%d %% %d = %d\n", 11, 4, 11 % 4); } +testPlus(){ printf("%d + %d = %d\n", 10, 4, 10 + 4); } +testMinus(){ printf("%d - %d = %d\n", 10, 4, 10 - 4); } +testShiftLeft(){ printf("%d << %d = %d\n", 10, 4, 10 << 4); } +testShiftRight(){ printf("%d >> %d = %d\n", 100, 4, 100 >> 4); } +testLess(){ printf("%d < %d = %d\n", 10, 4, 10 < 4); } +testLesEqual(){ printf("%d <= %d = %d\n", 10, 4, 10 <= 4); } +testGreater(){ printf("%d > %d = %d\n", 10, 4, 10 > 4); } +testGreaterEqual(){ printf("%d >= %d = %d\n", 10, 4, 10 >= 4); } +testEqualTo(){ printf("%d == %d = %d\n", 10, 4, 10 == 4); } +testNotEqualTo(){ printf("%d != %d = %d\n", 10, 4, 10 != 4); } +testBitAnd(){ printf("%d & %d = %d\n", 10, 7, 10 & 7); } +testBitXor(){ printf("%d ^ %d = %d\n", 10, 7, 10 ^ 7); } +testBitOr(){ printf("%d | %d = %d\n", 10, 4, 10 | 4); } +testAssignment(){ int a, b; a = 3; b = a; printf("b == %d\n", b); } +testLogicalAnd(){ printf("%d && %d = %d\n", 10, 4, 10 && 4); } +testLogicalOr(){ printf("%d || %d = %d\n", 10, 4, 10 || 4); } +testAddressOf(){ int a; printf("&a is %d\n", &a); } +testPointerIndirection(){ int a, b; a = &b; b = 17; printf("*%d = %d =?= %d\n", a, * (int*) a, b); } +testNegation(){ printf("-%d = %d\n", 10, -10); } +testUnaryPlus(){ printf("+%d = %d\n", 10, +10); } +testUnaryNot(){ printf("!%d = %d\n", 10, !10); } +testBitNot(){ printf("~%d = %d\n", 10, ~10); } + +main(a,b) { + testInc(); + testDec(); + testTimes(); + testDiv(); + testMod(); + testPlus(); + testMinus(); + testShiftLeft(); + testShiftRight(); + testLess(); + testLesEqual(); + testGreater(); + testGreaterEqual(); + testEqualTo(); + testNotEqualTo(); + testBitAnd(); + testBinXor(); + testBitOr(); + testAssignment(); + testLogicalAnd(); + testLogicalOr(); + testAddressOf(); + testPointerIndirection(); + testNegation(); + testUnaryPlus(); + testUnaryNot(); + testBitNot(); + return 0; +} \ No newline at end of file diff --git a/libacc/tests/data/expr2.c b/libacc/tests/data/expr2.c new file mode 100644 index 00000000000..04b6a38d3d2 --- /dev/null +++ b/libacc/tests/data/expr2.c @@ -0,0 +1,6 @@ +/* Test operators */ + +main() { + int a; + a = a++; +} diff --git a/libacc/tests/data/film.c b/libacc/tests/data/film.c new file mode 100644 index 00000000000..00c2d3604a5 --- /dev/null +++ b/libacc/tests/data/film.c @@ -0,0 +1,53 @@ +// Test logical and bitwise AND and OR + +int test(int x, int y) { + int v = x || y; + return v; +} + +int test2(int x, int y) { + if(x | y) { + return 1; + } else { + return 0; + } +} + +int test3(int x, int y) { + int v = x && y; + return v; +} + +int test4(int x, int y) { + if(x & y) { + return 1; + } else { + return 0; + } +} + +int main(int index) +{ + int x,y; + printf("testing...\n"); + int totalBad = 0; + for(y = 0; y < 2; y++) { + for(x = 0; x < 2; x++) { + int a = test(x,y); + int b = test2(x,y); + if (a != b) { + printf("Results differ: OR x=%d y=%d a=%d b=%d\n", x, y, a, b); + totalBad++; + } + a = test3(x,y); + b = test4(x,y); + if (a != b) { + printf("Results differ: AND x=%d y=%d a=%d b=%d\n", x, y, a, b); + totalBad++; + } + } + } + printf("Total bad: %d\n", totalBad); + return 0; +} + diff --git a/libacc/tests/data/float.c b/libacc/tests/data/float.c new file mode 100644 index 00000000000..f48b3d1ecb7 --- /dev/null +++ b/libacc/tests/data/float.c @@ -0,0 +1,57 @@ +int ftoi(float f) { + return f; +} + +int dtoi(double d) { + return d; +} + +float itof(int i) { + return i; +} + +double itod(int i) { + return i; +} + +float f0, f1; +double d0, d1; + +void testParseConsts() { + printf("Constants: %g %g %g %g %g %g %g %g %g\n", 0e1, 0E1, 0.f, .01f, + .01e0f, 1.0e-1, 1.0e1, 1.0e+1, + .1f); +} +void testVars(float arg0, float arg1, double arg2, double arg3) { + float local0, local1; + double local2, local3; + f0 = arg0; + f1 = arg1; + d0 = arg2; + d1 = arg3; + local0 = arg0; + local1 = arg1; + local2 = arg2; + local3 = arg3; + printf("globals: %g %g %g %g\n", f0, f1, d0, d1); + printf("args: %g %g %g %g\n", arg0, arg1, arg2, arg3); + printf("locals: %g %g %g %g\n", local0, local1, local2, local3); + + + printf("cast rval: %g %g\n", * (float*) & f1, * (double*) & d1); + + * (float*) & f0 = 1.1f; + * (double*) & d0 = 3.3; + printf("cast lval: %g %g %g %g\n", f0, f1, d0, d1); +} + +int main() { + testParseConsts(); + printf("int: %d float: %g double: %g\n", 1, 2.2f, 3.3); + printf(" ftoi(1.4f)=%d\n", ftoi(1.4f)); + printf(" dtoi(2.4)=%d\n", dtoi(2.4)); + printf(" itof(3)=%g\n", itof(3)); + printf(" itod(4)=%g\n", itod(4)); + testVars(1.0f, 2.0f, 3.0, 4.0); + return 0; +} diff --git a/libacc/tests/data/floatdouble.c b/libacc/tests/data/floatdouble.c new file mode 100644 index 00000000000..264c641b081 --- /dev/null +++ b/libacc/tests/data/floatdouble.c @@ -0,0 +1,9 @@ +int main() +{ + // Test coercing values when storing. + float a = 0.002; + double b = 0.1f; + int c = 10.002; + printf("%g %g %d\n", a, b, c); + return 0; +} diff --git a/libacc/tests/data/flops.c b/libacc/tests/data/flops.c new file mode 100644 index 00000000000..40b1b283ef0 --- /dev/null +++ b/libacc/tests/data/flops.c @@ -0,0 +1,158 @@ +// Test floating point operations. + +void unaryOps() { + // Unary ops + printf("-%g = %g\n", 1.1, -1.1); + printf("!%g = %d\n", 1.2, !1.2); + printf("!%g = %d\n", 0.0, !0.0); +} + +void binaryOps() { + printf("double op double:\n"); + printf("%g + %g = %g\n", 1.0, 2.0, 1.0 + 2.0); + printf("%g - %g = %g\n", 1.0, 2.0, 1.0 - 2.0); + printf("%g * %g = %g\n", 1.0, 2.0, 1.0 * 2.0); + printf("%g / %g = %g\n", 1.0, 2.0, 1.0 / 2.0); + + printf("float op float:\n"); + printf("%g + %g = %g\n", 1.0f, 2.0f, 1.0f + 2.0f); + printf("%g - %g = %g\n", 1.0f, 2.0f, 1.0f - 2.0f); + printf("%g * %g = %g\n", 1.0f, 2.0f, 1.0f * 2.0f); + printf("%g / %g = %g\n", 1.0f, 2.0f, 1.0f / 2.0f); + + printf("double op float:\n"); + printf("%g + %g = %g\n", 1.0, 2.0f, 1.0 + 2.0f); + printf("%g - %g = %g\n", 1.0, 2.0f, 1.0 - 2.0f); + printf("%g * %g = %g\n", 1.0, 2.0f, 1.0 * 2.0f); + printf("%g / %g = %g\n", 1.0, 2.0f, 1.0 / 2.0f); + + printf("double op int:\n"); + printf("%g + %d = %g\n", 1.0, 2, 1.0 + 2); + printf("%g - %d = %g\n", 1.0, 2, 1.0 - 2); + printf("%g * %d = %g\n", 1.0, 2, 1.0 * 2); + printf("%g / %d = %g\n", 1.0, 2, 1.0 / 2); + + printf("int op double:\n"); + printf("%d + %g = %g\n", 1, 2.0, 1 + 2.0); + printf("%d - %g = %g\n", 1, 2.0, 1 - 2.0); + printf("%d * %g = %g\n", 1, 2.0, 1 * 2.0); + printf("%d / %g = %g\n", 1, 2.0, 1 / 2.0); +} + +void comparisonTestdd(double a, double b) { + printf("%g op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsdd() { + printf("double op double:\n"); + comparisonTestdd(1.0, 2.0); + comparisonTestdd(1.0, 1.0); + comparisonTestdd(2.0, 1.0); +} + + +void comparisonTestdf(double a, float b) { + printf("%g op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsdf() { + printf("double op float:\n"); + comparisonTestdf(1.0, 2.0f); + comparisonTestdf(1.0, 1.0f); + comparisonTestdf(2.0, 1.0f); +} + +void comparisonTestff(float a, float b) { + printf("%g op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsff() { + printf("float op float:\n"); + comparisonTestff(1.0f, 2.0f); + comparisonTestff(1.0f, 1.0f); + comparisonTestff(2.0f, 1.0f); +} + +void comparisonTestid(int a, double b) { + printf("%d op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsid() { + printf("int op double:\n"); + comparisonTestid(1, 2.0); + comparisonTestid(1, 1.0); + comparisonTestid(2, 1.0); +} +void comparisonTestdi(double a, int b) { + printf("%g op %d: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsdi() { + printf("double op int:\n"); + comparisonTestdi(1.0f, 2); + comparisonTestdi(1.0f, 1); + comparisonTestdi(2.0f, 1); +} + +void comparisonOps() { + comparisonOpsdd(); + comparisonOpsdf(); + comparisonOpsff(); + comparisonOpsid(); + comparisonOpsdi(); +} + +int branch(double d) { + if (d) { + return 1; + } + return 0; +} + +void testBranching() { + printf("branching: %d %d %d\n", branch(-1.0), branch(0.0), branch(1.0)); +} + +void testpassi(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { + printf("testpassi: %d %d %d %d %d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h, i, j, k, l); +} + +void testpassf(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l) { + printf("testpassf: %g %g %g %g %g %g %g %g %g %g %g %g\n", a, b, c, d, e, f, g, h, i, j, k, l); +} + +void testpassd(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, double k, double l) { + printf("testpassd: %g %g %g %g %g %g %g %g %g %g %g %g\n", a, b, c, d, e, f, g, h, i, j, k, l); +} + +void testpassidf(int i, double d, float f) { + printf("testpassidf: %d %g %g\n", i, d, f); +} + +void testParameterPassing() { + float x; + testpassi(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + testpassf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + testpassd(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + testpassi(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f); + testpassf(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f); + testpassd(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f); + testpassi(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0); + testpassf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0); + testpassd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0); + testpassidf(1, 2.0, 3.0f); +} + +int main() { + unaryOps(); + binaryOps(); + comparisonOps(); + testBranching(); + testParameterPassing(); + return 0; +} diff --git a/libacc/tests/data/funcargs.c b/libacc/tests/data/funcargs.c new file mode 100644 index 00000000000..1dce2263c5b --- /dev/null +++ b/libacc/tests/data/funcargs.c @@ -0,0 +1,8 @@ +int f(int a,int, int c) { + return a + c; +} + +int main() { + return f(1,2,3); +} + diff --git a/libacc/tests/data/hello.c b/libacc/tests/data/hello.c new file mode 100644 index 00000000000..585ce6cadbd --- /dev/null +++ b/libacc/tests/data/hello.c @@ -0,0 +1,3 @@ +main(a,b) { + printf("Hello, world\n"); +} diff --git a/libacc/tests/data/inc.c b/libacc/tests/data/inc.c new file mode 100644 index 00000000000..14c09d18d54 --- /dev/null +++ b/libacc/tests/data/inc.c @@ -0,0 +1,14 @@ +// Check integer operations + +int main() { + int a = 0; + printf("%d\n", a++); + printf("%d\n", a++); + printf("%d\n", a--); + printf("%d\n", a--); + printf("%d\n", ++a); + printf("%d\n", ++a); + printf("%d\n", --a); + printf("%d\n", --a); + return a; +} diff --git a/libacc/tests/data/iops.c b/libacc/tests/data/iops.c new file mode 100644 index 00000000000..780e95d69e2 --- /dev/null +++ b/libacc/tests/data/iops.c @@ -0,0 +1,23 @@ +// Check integer operations + +void loops() { + int y; + printf("++\n"); + for(y = 0; y < 10; y++) { + printf("%d\n", y); + } + printf("--\n"); + for(y = 10; y >= 0; y--) { + printf("%d\n", y); + } +} + +void checkLiterals() { + printf("Literals: %d %d\n", 1, -1); +} + +int main() { + checkLiterals(); + loops(); + return 0; +} diff --git a/libacc/tests/data/locals.c b/libacc/tests/data/locals.c new file mode 100644 index 00000000000..f1ef363c487 --- /dev/null +++ b/libacc/tests/data/locals.c @@ -0,0 +1,71 @@ +int a; + +int f() { + int a; + // Undefined variable b + // printf("f 0: a = %d b = %d\n", a, b); + printf("f 0: a = %d\n", a); + a = 2; + printf("f 1: a = %d\n", a); +} + +int g(int a) { + printf("g 0: a = %d\n", a); + a = 3; + printf("g 1: a = %d\n", a); +} + +int h(int a) { + // int a; // gcc 4.3 says error: 'a' redeclared as different kind of symbol + + printf("h 0: a = %d\n", a); + a = 4; + printf("h 1: a = %d\n", a); +} + +// Already defined global +// int h() {} +int globCheck() { + fprintf(stdout, "globCheck()\n"); +} + +int fwdCheck() { + b(); + // Undefined forward reference + // c(); +} + +int b() { + printf("b()\n"); +} + +int nested() { + int a; + printf("nested 0: a = %d\n", a); + a = 50; + printf("nested 1: a = %d\n", a); + { + int a; + printf("nested 2: a = %d\n", a); + a = 51; + printf("nested 3: a = %d\n", a); + } + printf("nested 4: a = %d\n", a); +} + +int main() { + globCheck(); + fwdCheck(); + printf("main 0: a = %d\n", a); + a = 5; + printf("main 1: a = %d\n", a); + f(); + printf("main 2: a = %d\n", a); + g(77); + printf("main 3: a = %d\n", a); + h(30); + printf("main 4: a = %d\n", a); + nested(); + printf("main 5: a = %d\n", a); + return 0; +} diff --git a/libacc/tests/data/missing-main.c b/libacc/tests/data/missing-main.c new file mode 100644 index 00000000000..e73eec46157 --- /dev/null +++ b/libacc/tests/data/missing-main.c @@ -0,0 +1,4 @@ +/* No main. */ + +a() { +} \ No newline at end of file diff --git a/libacc/tests/data/otcc-ansi.c b/libacc/tests/data/otcc-ansi.c new file mode 100644 index 00000000000..72580e95f43 --- /dev/null +++ b/libacc/tests/data/otcc-ansi.c @@ -0,0 +1,466 @@ +// #include +int d, z, C, h, P, K, ac, q, G, v, Q, R, D, L, W, M; + +void E(int e) { + *(char*) D++ = e; +} + +void o() { + if (L) { + h = *(char*) L++; + if (h == 2) { + L = 0; + h = W; + } + } else + h = fgetc(Q); +} + +int X() { + return isalnum(h) | h == 95; +} + +void Y() { + if (h == 92) { + o(); + if (h == 110) + h = 10; + } +} + +void ad() { + int e, j, m; + while (isspace(h) | h == 35) { + if (h == 35) { + o(); + ad(); + if (d == 536) { + ad(); + E(32); + *(int*) d = 1; + *(int*) (d + 4) = D; + } + while (h != 10) { + E(h); + o(); + } + E(h); + E(2); + } + o(); + } + C = 0; + d = h; + if (X()) { + E(32); + M = D; + while (X()) { + E(h); + o(); + } + if (isdigit(d)) { + z = strtol(M, 0, 0); + d = 2; + } else { + *(char*) D = 32; + d = strstr(R, M - 1) - R; + *(char*) D = 0; + d = d * 8 + 256; + if (d > 536) { + d = P + d; + if (*(int*) d == 1) { + L = *(int*) (d + 4); + W = h; + o(); + ad(); + } + } + } + } else { + o(); + if (d == 39) { + d = 2; + Y(); + z = h; + o(); + o(); + } else if (d == 47 & h == 42) { + o(); + while (h) { + while (h != 42) + o(); + o(); + if (h == 47) + h = 0; + } + o(); + ad(); + } else { + e + = "++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b"; + while (j = *(char*) e++) { + m = *(char*) e++; + z = 0; + while ((C = *(char*) e++ - 98) < 0) + z = z * 64 + C + 64; + if (j == d & (m == h | m == 64)) { + if (m == h) { + o(); + d = 1; + } + break; + } + } + } + } +} + +void ae(int g) { + while( g&&g!=-1) { + *(char*) q++=g; + g=g>>8; + } +} + +void A(int e) { + int g; + while( e) { + g=*(int*) e; + *(int*) e=q-e-4; + e=g; + } +} + +int s(int g, int e) { + ae(g); + *(int*) q = e; + e = q; + q = q + 4; + return e; +} + +void H(int e) { + s(184,e); +} + +int B(int e) { + return s(233,e); +} + +int S(int j, int e) { + ae(1032325); + return s(132 + j, e); +} + +void Z(int e) { + ae( 49465); + H(0); + ae( 15); + ae( e+144); + ae( 192); +} + +void N(int j, int e) { + ae(j + 131); + s((e > -512 && e < 512) << 7 | 5, e); +} + +void T (int j) { + int g,e,m,aa; + g=1; + if( d == 34) { + H(v); + while( h!=34) { + Y (); + *(char*) v++=h; + o (); + } + *(char*) v=0; + v=v +4&-4; + o (); + ad(); + } + else { + aa=C; + m= z; + e=d; + ad(); + if( e == 2) { + H(m); + } + else if( aa == 2) { + T(0); + s(185,0); + if( e == 33)Z(m); + else ae( m); + } + else if( e == 40) { + w (); + ad(); + } + else if( e == 42) { + ad(); + e=d; + ad(); + ad(); + if( d == 42) { + ad(); + ad(); + ad(); + ad(); + e=0; + } + ad(); + T(0); + if( d == 61) { + ad(); + ae( 80); + w (); + ae( 89); + ae( 392+(e == 256)); + } + else if( e) { + if( e == 256)ae( 139); + else ae( 48655); + q++; + } + } + else if( e == 38) { + N(10,*(int*) d); + ad(); + } + else { + g=*(int*) e; + if(!g)g=dlsym(0,M); + if( d == 61&j) { + ad(); + w (); + N(6,g); + } + else if( d!= 40) { + N(8,g); + if( C == 11) { + N(0,g); + ae( z); + ad(); + } + } + } + } + if( d == 40) { + if( g == 1)ae( 80); + m= s(60545,0); + ad(); + j=0; + while( d!= 41) { + w (); + s(2393225,j); + if( d == 44)ad(); + j=j +4; + } + *(int*) m= j; + ad(); + if(!g) { + e=e +4; + *(int*) e=s(232,*(int*) e); + } + else if( g == 1) { + s(2397439,j); + j=j +4; + } + else { + s(232,g-q-5); + } + if( j)s(50305,j); + } +} + +void O (int j) { + int e,g,m; + if( j--== 1)T(1); + else { + O (j); + m= 0; + while( j == C) { + g=d; + e=z; + ad(); + if( j>8) { + m= S(e,m); + O (j); + } + else { + ae( 80); + O (j); + ae( 89); + if( j == 4|j == 5) { + Z(e); + } + else { + ae( e); + if( g == 37)ae( 146); + } + } + } + if( m&&j>8) { + m= S(e,m); + H(e^1); + B(5); + A(m); + H(e); + } + } +} + +void w() { + O(11); +} + +int U() { + w(); + return S(0, 0); +} + +void I (int j) { + int m,g,e; + if( d == 288) { + ad(); + ad(); + m= U (); + ad(); + I (j); + if( d == 312) { + ad(); + g=B(0); + A(m); + I (j); + A(g); + } + else { + A(m); + } + } + else if( d == 352|d == 504) { + e=d; + ad(); + ad(); + if( e == 352) { + g=q; + m= U (); + } + else { + if( d!= 59)w (); + ad(); + g=q; + m= 0; + if( d!= 59)m= U (); + ad(); + if( d!= 41) { + e=B(0); + w (); + B(g-q-5); + A(e); + g=e +4; + } + } + ad(); + I(&m); + B(g-q-5); + A(m); + } + else if( d == 123) { + ad(); + ab(1); + while( d!= 125)I (j); + ad(); + } + else { + if( d == 448) { + ad(); + if( d!= 59)w (); + K=B(K); + } + else if( d == 400) { + ad(); + *(int*) j=B(*(int*) j); + } + else if( d!= 59)w (); + ad(); + } +} + +void ab (int j) { + int m; + while( d == 256|d!=-1&!j) { + if( d == 256) { + ad(); + while( d!= 59) { + if( j) { + G=G +4; + *(int*) d=-G; + } + else { + *(int*) d=v; + v=v +4; + } + ad(); + if( d == 44)ad() ; + } + ad(); + } + else { + A(*(int*)(d +4)); + *(int*) d=q; + ad(); + ad(); + m= 8; + while( d!= 41) { + *(int*) d=m; + m= m +4; + ad(); + if( d == 44)ad(); + } + ad(); + K=G=0; + ae( 15042901); + m= s(60545,0); + I(0); + A(K); + ae( 50121); + *(int*) m= G; + } + } +} + +int run(int g, int e) { + return (*(int(*)()) *(int*) (P + 592))(g, e); +} + +int main(int g, int e) { + int result; + Q = stdin; + if (g-- > 1) { + e = e + 4; + Q = fopen(*(int*) e, "r"); + if (!Q) { + fprintf(stderr, "otcc-ansi.c: could not open file %s\n", *(int*) e); + return -2; + } + } + D = strcpy(R = calloc(1, 99999), " int if else while break return for define main ") + 48; + v = calloc(1, 99999); + q = ac = calloc(1, 99999); + P = calloc(1, 99999); + o(); + ad(); + ab(0); + if (mprotect(ac & (~ 4095), (99999 + 4095) & (~ 4095), 7)) { + printf("Mprotect failed. %d\n", errno); + return -1; + } + fprintf(stderr, "otcc-ansi.c: About to execute compiled code:\n"); + result = run(g, e); + fprintf(stderr, "atcc-ansi.c: result: %d\n", result); + return result; +} + diff --git a/libacc/tests/data/otcc-noinclude.c b/libacc/tests/data/otcc-noinclude.c new file mode 100644 index 00000000000..530f9e2e8f8 --- /dev/null +++ b/libacc/tests/data/otcc-noinclude.c @@ -0,0 +1,446 @@ +// #include +#define k *(int*) +#define a if( +#define c ad() +#define i else +#define p while( +#define x *(char*) +#define b == +#define V =calloc(1,99999) +#define f () +#define J return +#define l ae( +#define n e) +#define u d!= +#define F int +#define y (j) +#define r m= +#define t +4 +F d,z,C,h,P,K,ac,q,G,v,Q,R,D,L,W,M; +E(n{ +x D++=e; +} +o f{ +a L){ +h=x L++; +a h b 2){ +L=0; +h=W; +} +} +i h=fgetc(Q); +} +X f{ +J isalnum(h)|h b 95; +} +Y f{ +a h b 92){ +o f; +a h b 110)h=10; +} +} +c{ +F e,j,m; +p isspace(h)|h b 35){ +a h b 35){ +o f; +c; +a d b 536){ +c; +E(32); +k d=1; +k(d t)=D; +} +p h!=10){ +E(h); +o f; +} +E(h); +E(2); +} +o f; +} +C=0; +d=h; +a X f){ +E(32); +M=D; +p X f){ +E(h); +o f; +} +a isdigit(d)){ +z=strtol(M,0,0); +d=2; +} +i{ +x D=32; +d=strstr(R,M-1)-R; +x D=0; +d=d*8+256; +a d>536){ +d=P+d; +a k d b 1){ +L=k(d t); +W=h; +o f; +c; +} +} +} +} +i{ +o f; +a d b 39){ +d=2; +Y f; +z=h; +o f; +o f; +} +i a d b 47&h b 42){ +o f; +p h){ +p h!=42)o f; +o f; +a h b 47)h=0; +} +o f; +c; +} +i{ +e="++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b"; +p j=x e++){ +r x e++; +z=0; +p(C=x e++-98)<0)z=z*64+C+64; +a j b d&(m b h|m b 64)){ +a m b h){ +o f; +d=1; +} +break; +} +} +} +} +} +l g){ +p g&&g!=-1){ +x q++=g; +g=g>>8; +} +} +A(n{ +F g; +p n{ +g=k e; +k e=q-e-4; +e=g; +} +} +s(g,n{ +l g); +k q=e; +e=q; +q=q t; +J e; +} +H(n{ +s(184,n; +} +B(n{ +J s(233,n; +} +S(j,n{ +l 1032325); +J s(132+j,n; +} +Z(n{ +l 49465); +H(0); +l 15); +l e+144); +l 192); +} +N(j,n{ +l j+131); +s((e<512)<<7|5,n; +} +T y{ +F g,e,m,aa; +g=1; +a d b 34){ +H(v); +p h!=34){ +Y f; +x v++=h; +o f; +} +x v=0; +v=v t&-4; +o f; +c; +} +i{ +aa=C; +r z; +e=d; +c; +a e b 2){ +H(m); +} +i a aa b 2){ +T(0); +s(185,0); +a e b 33)Z(m); +i l m); +} +i a e b 40){ +w f; +c; +} +i a e b 42){ +c; +e=d; +c; +c; +a d b 42){ +c; +c; +c; +c; +e=0; +} +c; +T(0); +a d b 61){ +c; +l 80); +w f; +l 89); +l 392+(e b 256)); +} +i a n{ +a e b 256)l 139); +i l 48655); +q++; +} +} +i a e b 38){ +N(10,k d); +c; +} +i{ +g=k e; +a!g)g=dlsym(0,M); +a d b 61&j){ +c; +w f; +N(6,g); +} +i a u 40){ +N(8,g); +a C b 11){ +N(0,g); +l z); +c; +} +} +} +} +a d b 40){ +a g b 1)l 80); +r s(60545,0); +c; +j=0; +p u 41){ +w f; +s(2393225,j); +a d b 44)c; +j=j t; +} +k r j; +c; +a!g){ +e=e t; +k e=s(232,k n; +} +i a g b 1){ +s(2397439,j); +j=j t; +} +i{ +s(232,g-q-5); +} +a j)s(50305,j); +} +} +O y{ +F e,g,m; +a j--b 1)T(1); +i{ +O y; +r 0; +p j b C){ +g=d; +e=z; +c; +a j>8){ +r S(e,m); +O y; +} +i{ +l 80); +O y; +l 89); +a j b 4|j b 5){ +Z(n; +} +i{ +l n; +a g b 37)l 146); +} +} +} +a m&&j>8){ +r S(e,m); +H(e^1); +B(5); +A(m); +H(n; +} +} +} +w f{ +O(11); +} +U f{ +w f; +J S(0,0); +} +I y{ +F m,g,e; +a d b 288){ +c; +c; +r U f; +c; +I y; +a d b 312){ +c; +g=B(0); +A(m); +I y; +A(g); +} +i{ +A(m); +} +} +i a d b 352|d b 504){ +e=d; +c; +c; +a e b 352){ +g=q; +r U f; +} +i{ +a u 59)w f; +c; +g=q; +r 0; +a u 59)r U f; +c; +a u 41){ +e=B(0); +w f; +B(g-q-5); +A(n; +g=e t; +} +} +c; +I(&m); +B(g-q-5); +A(m); +} +i a d b 123){ +c; +ab(1); +p u 125)I y; +c; +} +i{ +a d b 448){ +c; +a u 59)w f; +K=B(K); +} +i a d b 400){ +c; +k j=B(k j); +} +i a u 59)w f; +c; +} +} +ab y{ +F m; +p d b 256|u-1&!j){ +a d b 256){ +c; +p u 59){ +a j){ +G=G t; +k d=-G; +} +i{ +k d=v; +v=v t; +} +c; +a d b 44)c; +} +c; +} +i{ +A(k(d t)); +k d=q; +c; +c; +r 8; +p u 41){ +k d=m; +r m t; +c; +a d b 44)c; +} +c; +K=G=0; +l 15042901); +r s(60545,0); +I(0); +A(K); +l 50121); +k r G; +} +} +} +main(g,n{ +Q=stdin; +a g-->1){ +e=e t; +Q=fopen(k e,"r"); +} +D=strcpy(R V," int if else while break return for define main ")+48; +v V; +q=ac V; +P V; +o f; +c; +ab(0); +J(*(int(*)f)k(P+592))(g,n; +} + diff --git a/libacc/tests/data/otcc.c b/libacc/tests/data/otcc.c new file mode 100644 index 00000000000..433ae2ea65f --- /dev/null +++ b/libacc/tests/data/otcc.c @@ -0,0 +1,448 @@ +#include +#define k *(int*) +#define a if( +#define c ad() +#define i else +#define p while( +#define x *(char*) +#define b == +#define V =calloc(1,99999) +#define f () +#define J return +#define l ae( +#define n e) +#define u d!= +#define F int +#define y (j) +#define r m= +#define t +4 +F d,z,C,h,P,K,ac,q,G,v,Q,R,D,L,W,M; +E(n{ +x D++=e; +} +o f{ +a L){ +h=x L++; +a h b 2){ +L=0; +h=W; +} +} +i h=fgetc(Q); +} +X f{ +J isalnum(h)|h b 95; +} +Y f{ +a h b 92){ +o f; +a h b 110)h=10; +} +} +c{ +F e,j,m; +p isspace(h)|h b 35){ +a h b 35){ +o f; +c; +a d b 536){ +c; +E(32); +k d=1; +k(d t)=D; +} +p h!=10){ +E(h); +o f; +} +E(h); +E(2); +} +o f; +} +C=0; +d=h; +a X f){ +E(32); +M=D; +p X f){ +E(h); +o f; +} +a isdigit(d)){ +z=strtol(M,0,0); +d=2; +} +i{ +x D=32; +d=strstr(R,M-1)-R; +x D=0; +d=d*8+256; +a d>536){ +d=P+d; +a k d b 1){ +L=k(d t); +W=h; +o f; +c; +} +} +} +} +i{ +o f; +a d b 39){ +d=2; +Y f; +z=h; +o f; +o f; +} +i a d b 47&h b 42){ +o f; +p h){ +p h!=42)o f; +o f; +a h b 47)h=0; +} +o f; +c; +} +i{ +e="++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b"; +p j=x e++){ +r x e++; +z=0; +p(C=x e++-98)<0)z=z*64+C+64; +a j b d&(m b h|m b 64)){ +a m b h){ +o f; +d=1; +} +break; +} +} +} +} +} +l g){ +p g&&g!=-1){ +x q++=g; +g=g>>8; +} +} +A(n{ +F g; +p n{ +g=k e; +k e=q-e-4; +e=g; +} +} +s(g,n{ +l g); +k q=e; +e=q; +q=q t; +J e; +} +H(n{ +s(184,n; +} +B(n{ +J s(233,n; +} +S(j,n{ +l 1032325); +J s(132+j,n; +} +Z(n{ +l 49465); +H(0); +l 15); +l e+144); +l 192); +} +N(j,n{ +l j+131); +s((e<512)<<7|5,n; +} +T y{ +F g,e,m,aa; +g=1; +a d b 34){ +H(v); +p h!=34){ +Y f; +x v++=h; +o f; +} +x v=0; +v=v t&-4; +o f; +c; +} +i{ +aa=C; +r z; +e=d; +c; +a e b 2){ +H(m); +} +i a aa b 2){ +T(0); +s(185,0); +a e b 33)Z(m); +i l m); +} +i a e b 40){ +w f; +c; +} +i a e b 42){ +c; +e=d; +c; +c; +a d b 42){ +c; +c; +c; +c; +e=0; +} +c; +T(0); +a d b 61){ +c; +l 80); +w f; +l 89); +l 392+(e b 256)); +} +i a n{ +a e b 256)l 139); +i l 48655); +q++; +} +} +i a e b 38){ +N(10,k d); +c; +} +i{ +g=k e; +a!g)g=dlsym(0,M); +a d b 61&j){ +c; +w f; +N(6,g); +} +i a u 40){ +N(8,g); +a C b 11){ +N(0,g); +l z); +c; +} +} +} +} +a d b 40){ +a g b 1)l 80); +r s(60545,0); +c; +j=0; +p u 41){ +w f; +s(2393225,j); +a d b 44)c; +j=j t; +} +k r j; +c; +a!g){ +e=e t; +k e=s(232,k n; +} +i a g b 1){ +s(2397439,j); +j=j t; +} +i{ +s(232,g-q-5); +} +a j)s(50305,j); +} +} +O y{ +F e,g,m; +a j--b 1)T(1); +i{ +O y; +r 0; +p j b C){ +g=d; +e=z; +c; +a j>8){ +r S(e,m); +O y; +} +i{ +l 80); +O y; +l 89); +a j b 4|j b 5){ +Z(n; +} +i{ +l n; +a g b 37)l 146); +} +} +} +a m&&j>8){ +r S(e,m); +H(e^1); +B(5); +A(m); +H(n; +} +} +} +w f{ +O(11); +} +U f{ +w f; +J S(0,0); +} +I y{ +F m,g,e; +a d b 288){ +c; +c; +r U f; +c; +I y; +a d b 312){ +c; +g=B(0); +A(m); +I y; +A(g); +} +i{ +A(m); +} +} +i a d b 352|d b 504){ +e=d; +c; +c; +a e b 352){ +g=q; +r U f; +} +i{ +a u 59)w f; +c; +g=q; +r 0; +a u 59)r U f; +c; +a u 41){ +e=B(0); +w f; +B(g-q-5); +A(n; +g=e t; +} +} +c; +I(&m); +B(g-q-5); +A(m); +} +i a d b 123){ +c; +ab(1); +p u 125)I y; +c; +} +i{ +a d b 448){ +c; +a u 59)w f; +K=B(K); +} +i a d b 400){ +c; +k j=B(k j); +} +i a u 59)w f; +c; +} +} +ab y{ +F m; +p d b 256|u-1&!j){ +a d b 256){ +c; +p u 59){ +a j){ +G=G t; +k d=-G; +} +i{ +k d=v; +v=v t; +} +c; +a d b 44)c; +} +c; +} +i{ +A(k(d t)); +k d=q; +c; +c; +r 8; +p u 41){ +k d=m; +r m t; +c; +a d b 44)c; +} +c; +K=G=0; +l 15042901); +r s(60545,0); +I(0); +A(K); +l 50121); +k r G; +} +} +} +main(g,n{ +Q=stdin; +a g-->1){ +e=e t; +Q=fopen(k e,"r"); +} +D=strcpy(R V," int if else while break return for define main ")+48; +v V; +q=ac V; +P V; +o f; +c; +ab(0); +mprotect(ac & (~ 4095), (99999 + 4095) & (~ 4095), 7); +fprintf(stderr, "otcc.c: about to execute compiled code.\n"); +J(*(int(*)f)k(P+592))(g,n; +} + diff --git a/libacc/tests/data/pointers.c b/libacc/tests/data/pointers.c new file mode 100644 index 00000000000..461ebeb4684 --- /dev/null +++ b/libacc/tests/data/pointers.c @@ -0,0 +1,15 @@ +int main() { + int* pa = (int*) malloc(100); + int* pb = pa + 1; + int* pc = (int*) 0; + *pa = 1; + *pb = 2; + printf("Pointer difference: %d %d\n", pb - pa, ((int) pb) - ((int) pa)); + int c = * (pa + 1); + printf("Pointer addition: %d\n", c); + printf("Pointer comparison to zero: %d %d %d\n", pa == 0, pb == 0, pc == 0); + printf("Pointer comparison: %d %d %d %d %d\n", pa < pb, pa == pb, pa > pb, ! pb, ! pc); + free(pa); + return 0; +} + diff --git a/libacc/tests/data/pointers2.c b/libacc/tests/data/pointers2.c new file mode 100644 index 00000000000..69e402f6990 --- /dev/null +++ b/libacc/tests/data/pointers2.c @@ -0,0 +1,35 @@ +// Test multiple levels of indirection + +void testsingle() { + int a = 0; + int* pa = &a; + printf("a = %d, *pa = %d\n", a, *pa); + *pa = 2; + printf("a = %d, *pa = %d\n", a, *pa); +} + +void testdouble() { + int a = 0; + int* pa = &a; + int** ppa = &pa; + printf("a = %d, *pa = %d **ppa = %d\n", a, *pa, **ppa); + **ppa = 2; + printf("a = %d, *pa = %d **ppa = %d\n", a, *pa, **ppa); +} + +void testtripple() { + int a = 0; + int* pa = &a; + int** ppa = &pa; + int*** pppa = &ppa; + printf("a = %d, *pa = %d **ppa = %d\n ***pppa = %d", a, *pa, **ppa, ***pppa); + ***pppa = 2; + printf("a = %d, *pa = %d **ppa = %d\n ***pppa = %d", a, *pa, **ppa, ***pppa); +} + +int main() { + testsingle(); + testdouble(); + testdouble(); + return 0; +} diff --git a/libacc/tests/data/returnval-ansi.c b/libacc/tests/data/returnval-ansi.c new file mode 100644 index 00000000000..6b53fd54bdf --- /dev/null +++ b/libacc/tests/data/returnval-ansi.c @@ -0,0 +1,8 @@ + +int main(int argc, char** argv) { + return f(); +} + +int f() { + return 42; +} diff --git a/libacc/tests/data/returnval.c b/libacc/tests/data/returnval.c new file mode 100644 index 00000000000..1cf5bae9318 --- /dev/null +++ b/libacc/tests/data/returnval.c @@ -0,0 +1,4 @@ +main() { + return 42; +} + diff --git a/libacc/tests/data/rollo3.c b/libacc/tests/data/rollo3.c new file mode 100644 index 00000000000..b21c12fc302 --- /dev/null +++ b/libacc/tests/data/rollo3.c @@ -0,0 +1,9 @@ + +float fabsf(float); + +int main(void* con, int ft, int launchID) +{ + float f = fabsf(-10.0f); + return f; +} + diff --git a/libacc/tests/data/short.c b/libacc/tests/data/short.c new file mode 100644 index 00000000000..5e222f33aa8 --- /dev/null +++ b/libacc/tests/data/short.c @@ -0,0 +1,6 @@ +short a = 3; +int main() { + short* b = &a; + *b = *b - 5; + return a; +} diff --git a/libacc/tests/data/simplest.c b/libacc/tests/data/simplest.c new file mode 100644 index 00000000000..bae895adcb6 --- /dev/null +++ b/libacc/tests/data/simplest.c @@ -0,0 +1 @@ +main() {} diff --git a/libacc/tests/data/structs.c b/libacc/tests/data/structs.c new file mode 100644 index 00000000000..dd81af31edf --- /dev/null +++ b/libacc/tests/data/structs.c @@ -0,0 +1,95 @@ +// struct definition and declaration +struct a { + int a; + int b; +} c; + +// Useless, but legal struct declaration +struct { + int x; +}; + +// Useful anonymous struct declaration +struct { + int y; +} anon1, anon2; + +// forward declarations +struct a; +struct b; +struct c; + +struct b {int a; int b; }; + +// struct c {b g; }; // syntax error. + +// struct s {float c,a,b,c;} s; // duplicate struct member + +struct c {struct b g; }; + +// struct a { int w; }; // error + +void testCopying() { + struct a {int a[10]; char c;} a, b; + a.c = 37; + b.c = 38; + b = a; + printf("testCopying: %d == %d\n", a.c, b.c); +} + +void testUnion() { + union u; + union u {float f;int i;} u; + u.f = 1.0f; + printf("testUnion: %g == 0x%08x\n", u.f, u.i); +} + +struct v {float x, y, z, w; }; + +void add(struct v* result, struct v* a, struct v* b) { + result->x = a->x + b->x; + result->y = a->y + b->y; + result->z = a->z + b->z; + result->w = a->w + b->w; +} + +void set(struct v* v, float x, float y, float z, float w) { + v->x = x; + v->y = y; + v->z = z; + v->w = w; +} + +void print(struct v* v) { + printf("(%g, %g, %g, %g)\n", v->x, v->y, v->z, v->w); +} + +void testArgs() { + struct v a, b, c; + set(&a, 1.0f, 2.0f, 3.0f, 4.0f); + set(&b, 5.0f, 6.0f, 7.0f, 8.0f); + add(&c, &a, &b); + printf("testArgs: "); + print(&c); +} + +int main() { + anon1.y = 3; + anon2.y = anon1.y; + + testCopying(); + testUnion(); + testArgs(); + + struct c cc; + cc.g.a = 3; + c.a = 1; + c.b = 3; + struct a {int x, y; } z; + // struct a {int x, y; } z2; + z.x = c.a; + struct a *pA; + pA = &z; + pA->x += 5; + return pA->x; +} diff --git a/libacc/tests/data/testStringConcat.c b/libacc/tests/data/testStringConcat.c new file mode 100644 index 00000000000..bf06ae18ef2 --- /dev/null +++ b/libacc/tests/data/testStringConcat.c @@ -0,0 +1,4 @@ +int main() { + return printf("Hello" "," " world\n"); +} + diff --git a/libacc/tests/disassem.cpp b/libacc/tests/disassem.cpp new file mode 100644 index 00000000000..ac35342fde2 --- /dev/null +++ b/libacc/tests/disassem.cpp @@ -0,0 +1,711 @@ +/* $NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $ */ + +/*- + * Copyright (c) 1996 Mark Brinicombe. + * Copyright (c) 1996 Brini. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Brini. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * RiscBSD kernel project + * + * db_disasm.c + * + * Kernel disassembler + * + * Created : 10/02/96 + * + * Structured after the sparc/sparc/db_disasm.c by David S. Miller & + * Paul Kranenburg + * + * This code is not complete. Not all instructions are disassembled. + */ + +#include +//__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/arm/arm/disassem.c,v 1.2 2005/01/05 21:58:47 imp Exp $"); +#include +#include +#include + +#include "disassem.h" +#include "armreg.h" +//#include + +/* + * General instruction format + * + * insn[cc][mod] [operands] + * + * Those fields with an uppercase format code indicate that the field + * follows directly after the instruction before the separator i.e. + * they modify the instruction rather than just being an operand to + * the instruction. The only exception is the writeback flag which + * follows a operand. + * + * + * 2 - print Operand 2 of a data processing instruction + * d - destination register (bits 12-15) + * n - n register (bits 16-19) + * s - s register (bits 8-11) + * o - indirect register rn (bits 16-19) (used by swap) + * m - m register (bits 0-3) + * a - address operand of ldr/str instruction + * e - address operand of ldrh/strh instruction + * l - register list for ldm/stm instruction + * f - 1st fp operand (register) (bits 12-14) + * g - 2nd fp operand (register) (bits 16-18) + * h - 3rd fp operand (register/immediate) (bits 0-4) + * b - branch address + * t - thumb branch address (bits 24, 0-23) + * k - breakpoint comment (bits 0-3, 8-19) + * X - block transfer type + * Y - block transfer type (r13 base) + * c - comment field bits(0-23) + * p - saved or current status register + * F - PSR transfer fields + * D - destination-is-r15 (P) flag on TST, TEQ, CMP, CMN + * L - co-processor transfer size + * S - set status flag + * P - fp precision + * Q - fp precision (for ldf/stf) + * R - fp rounding + * v - co-processor data transfer registers + addressing mode + * W - writeback flag + * x - instruction in hex + * # - co-processor number + * y - co-processor data processing registers + * z - co-processor register transfer registers + */ + +struct arm32_insn { + u_int mask; + u_int pattern; + const char* name; + const char* format; +}; + +static const struct arm32_insn arm32_i[] = { + { 0x0fffffff, 0x0ff00000, "imb", "c" }, /* Before swi */ + { 0x0fffffff, 0x0ff00001, "imbrange", "c" }, /* Before swi */ + { 0x0f000000, 0x0f000000, "swi", "c" }, + { 0xfe000000, 0xfa000000, "blx", "t" }, /* Before b and bl */ + { 0x0f000000, 0x0a000000, "b", "b" }, + { 0x0f000000, 0x0b000000, "bl", "b" }, + { 0x0fe000f0, 0x00000090, "mul", "Snms" }, + { 0x0fe000f0, 0x00200090, "mla", "Snmsd" }, + { 0x0fe000f0, 0x00800090, "umull", "Sdnms" }, + { 0x0fe000f0, 0x00c00090, "smull", "Sdnms" }, + { 0x0fe000f0, 0x00a00090, "umlal", "Sdnms" }, + { 0x0fe000f0, 0x00e00090, "smlal", "Sdnms" }, + { 0x0d700000, 0x04200000, "strt", "daW" }, + { 0x0d700000, 0x04300000, "ldrt", "daW" }, + { 0x0d700000, 0x04600000, "strbt", "daW" }, + { 0x0d700000, 0x04700000, "ldrbt", "daW" }, + { 0x0c500000, 0x04000000, "str", "daW" }, + { 0x0c500000, 0x04100000, "ldr", "daW" }, + { 0x0c500000, 0x04400000, "strb", "daW" }, + { 0x0c500000, 0x04500000, "ldrb", "daW" }, + { 0x0e1f0000, 0x080d0000, "stm", "YnWl" },/* separate out r13 base */ + { 0x0e1f0000, 0x081d0000, "ldm", "YnWl" },/* separate out r13 base */ + { 0x0e100000, 0x08000000, "stm", "XnWl" }, + { 0x0e100000, 0x08100000, "ldm", "XnWl" }, + { 0x0e1000f0, 0x00100090, "ldrb", "deW" }, + { 0x0e1000f0, 0x00000090, "strb", "deW" }, + { 0x0e1000f0, 0x001000d0, "ldrsb", "deW" }, + { 0x0e1000f0, 0x001000b0, "ldrh", "deW" }, + { 0x0e1000f0, 0x000000b0, "strh", "deW" }, + { 0x0e1000f0, 0x001000f0, "ldrsh", "deW" }, + { 0x0f200090, 0x00200090, "und", "x" }, /* Before data processing */ + { 0x0e1000d0, 0x000000d0, "und", "x" }, /* Before data processing */ + { 0x0ff00ff0, 0x01000090, "swp", "dmo" }, + { 0x0ff00ff0, 0x01400090, "swpb", "dmo" }, + { 0x0fbf0fff, 0x010f0000, "mrs", "dp" }, /* Before data processing */ + { 0x0fb0fff0, 0x0120f000, "msr", "pFm" },/* Before data processing */ + { 0x0fb0f000, 0x0320f000, "msr", "pF2" },/* Before data processing */ + { 0x0ffffff0, 0x012fff10, "bx", "m" }, + { 0x0fff0ff0, 0x016f0f10, "clz", "dm" }, + { 0x0ffffff0, 0x012fff30, "blx", "m" }, + { 0xfff000f0, 0xe1200070, "bkpt", "k" }, + { 0x0de00000, 0x00000000, "and", "Sdn2" }, + { 0x0de00000, 0x00200000, "eor", "Sdn2" }, + { 0x0de00000, 0x00400000, "sub", "Sdn2" }, + { 0x0de00000, 0x00600000, "rsb", "Sdn2" }, + { 0x0de00000, 0x00800000, "add", "Sdn2" }, + { 0x0de00000, 0x00a00000, "adc", "Sdn2" }, + { 0x0de00000, 0x00c00000, "sbc", "Sdn2" }, + { 0x0de00000, 0x00e00000, "rsc", "Sdn2" }, + { 0x0df00000, 0x01100000, "tst", "Dn2" }, + { 0x0df00000, 0x01300000, "teq", "Dn2" }, + { 0x0df00000, 0x01500000, "cmp", "Dn2" }, + { 0x0df00000, 0x01700000, "cmn", "Dn2" }, + { 0x0de00000, 0x01800000, "orr", "Sdn2" }, + { 0x0de00000, 0x01a00000, "mov", "Sd2" }, + { 0x0de00000, 0x01c00000, "bic", "Sdn2" }, + { 0x0de00000, 0x01e00000, "mvn", "Sd2" }, + { 0x0ff08f10, 0x0e000100, "adf", "PRfgh" }, + { 0x0ff08f10, 0x0e100100, "muf", "PRfgh" }, + { 0x0ff08f10, 0x0e200100, "suf", "PRfgh" }, + { 0x0ff08f10, 0x0e300100, "rsf", "PRfgh" }, + { 0x0ff08f10, 0x0e400100, "dvf", "PRfgh" }, + { 0x0ff08f10, 0x0e500100, "rdf", "PRfgh" }, + { 0x0ff08f10, 0x0e600100, "pow", "PRfgh" }, + { 0x0ff08f10, 0x0e700100, "rpw", "PRfgh" }, + { 0x0ff08f10, 0x0e800100, "rmf", "PRfgh" }, + { 0x0ff08f10, 0x0e900100, "fml", "PRfgh" }, + { 0x0ff08f10, 0x0ea00100, "fdv", "PRfgh" }, + { 0x0ff08f10, 0x0eb00100, "frd", "PRfgh" }, + { 0x0ff08f10, 0x0ec00100, "pol", "PRfgh" }, + { 0x0f008f10, 0x0e000100, "fpbop", "PRfgh" }, + { 0x0ff08f10, 0x0e008100, "mvf", "PRfh" }, + { 0x0ff08f10, 0x0e108100, "mnf", "PRfh" }, + { 0x0ff08f10, 0x0e208100, "abs", "PRfh" }, + { 0x0ff08f10, 0x0e308100, "rnd", "PRfh" }, + { 0x0ff08f10, 0x0e408100, "sqt", "PRfh" }, + { 0x0ff08f10, 0x0e508100, "log", "PRfh" }, + { 0x0ff08f10, 0x0e608100, "lgn", "PRfh" }, + { 0x0ff08f10, 0x0e708100, "exp", "PRfh" }, + { 0x0ff08f10, 0x0e808100, "sin", "PRfh" }, + { 0x0ff08f10, 0x0e908100, "cos", "PRfh" }, + { 0x0ff08f10, 0x0ea08100, "tan", "PRfh" }, + { 0x0ff08f10, 0x0eb08100, "asn", "PRfh" }, + { 0x0ff08f10, 0x0ec08100, "acs", "PRfh" }, + { 0x0ff08f10, 0x0ed08100, "atn", "PRfh" }, + { 0x0f008f10, 0x0e008100, "fpuop", "PRfh" }, + { 0x0e100f00, 0x0c000100, "stf", "QLv" }, + { 0x0e100f00, 0x0c100100, "ldf", "QLv" }, + { 0x0ff00f10, 0x0e000110, "flt", "PRgd" }, + { 0x0ff00f10, 0x0e100110, "fix", "PRdh" }, + { 0x0ff00f10, 0x0e200110, "wfs", "d" }, + { 0x0ff00f10, 0x0e300110, "rfs", "d" }, + { 0x0ff00f10, 0x0e400110, "wfc", "d" }, + { 0x0ff00f10, 0x0e500110, "rfc", "d" }, + { 0x0ff0ff10, 0x0e90f110, "cmf", "PRgh" }, + { 0x0ff0ff10, 0x0eb0f110, "cnf", "PRgh" }, + { 0x0ff0ff10, 0x0ed0f110, "cmfe", "PRgh" }, + { 0x0ff0ff10, 0x0ef0f110, "cnfe", "PRgh" }, + { 0xff100010, 0xfe000010, "mcr2", "#z" }, + { 0x0f100010, 0x0e000010, "mcr", "#z" }, + { 0xff100010, 0xfe100010, "mrc2", "#z" }, + { 0x0f100010, 0x0e100010, "mrc", "#z" }, + { 0xff000010, 0xfe000000, "cdp2", "#y" }, + { 0x0f000010, 0x0e000000, "cdp", "#y" }, + { 0xfe100090, 0xfc100000, "ldc2", "L#v" }, + { 0x0e100090, 0x0c100000, "ldc", "L#v" }, + { 0xfe100090, 0xfc000000, "stc2", "L#v" }, + { 0x0e100090, 0x0c000000, "stc", "L#v" }, + { 0xf550f000, 0xf550f000, "pld", "ne" }, + { 0x0ff00ff0, 0x01000050, "qaad", "dmn" }, + { 0x0ff00ff0, 0x01400050, "qdaad", "dmn" }, + { 0x0ff00ff0, 0x01600050, "qdsub", "dmn" }, + { 0x0ff00ff0, 0x01200050, "dsub", "dmn" }, + { 0x0ff000f0, 0x01000080, "smlabb", "nmsd" }, // d & n inverted!! + { 0x0ff000f0, 0x010000a0, "smlatb", "nmsd" }, // d & n inverted!! + { 0x0ff000f0, 0x010000c0, "smlabt", "nmsd" }, // d & n inverted!! + { 0x0ff000f0, 0x010000e0, "smlatt", "nmsd" }, // d & n inverted!! + { 0x0ff000f0, 0x01400080, "smlalbb","ndms" }, // d & n inverted!! + { 0x0ff000f0, 0x014000a0, "smlaltb","ndms" }, // d & n inverted!! + { 0x0ff000f0, 0x014000c0, "smlalbt","ndms" }, // d & n inverted!! + { 0x0ff000f0, 0x014000e0, "smlaltt","ndms" }, // d & n inverted!! + { 0x0ff000f0, 0x01200080, "smlawb", "nmsd" }, // d & n inverted!! + { 0x0ff0f0f0, 0x012000a0, "smulwb","nms" }, // d & n inverted!! + { 0x0ff000f0, 0x012000c0, "smlawt", "nmsd" }, // d & n inverted!! + { 0x0ff0f0f0, 0x012000e0, "smulwt","nms" }, // d & n inverted!! + { 0x0ff0f0f0, 0x01600080, "smulbb","nms" }, // d & n inverted!! + { 0x0ff0f0f0, 0x016000a0, "smultb","nms" }, // d & n inverted!! + { 0x0ff0f0f0, 0x016000c0, "smulbt","nms" }, // d & n inverted!! + { 0x0ff0f0f0, 0x016000e0, "smultt","nms" }, // d & n inverted!! + { 0x00000000, 0x00000000, NULL, NULL } +}; + +static char const arm32_insn_conditions[][4] = { + "eq", "ne", "cs", "cc", + "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", + "gt", "le", "", "nv" +}; + +static char const insn_block_transfers[][4] = { + "da", "ia", "db", "ib" +}; + +static char const insn_stack_block_transfers[][4] = { + "ed", "ea", "fd", "fa" +}; + +static char const op_shifts[][4] = { + "lsl", "lsr", "asr", "ror" +}; + +static char const insn_fpa_rounding[][2] = { + "", "p", "m", "z" +}; + +static char const insn_fpa_precision[][2] = { + "s", "d", "e", "p" +}; + +static char const insn_fpaconstants[][8] = { + "0.0", "1.0", "2.0", "3.0", + "4.0", "5.0", "0.5", "10.0" +}; + +#define insn_condition(x) arm32_insn_conditions[(x >> 28) & 0x0f] +#define insn_blktrans(x) insn_block_transfers[(x >> 23) & 3] +#define insn_stkblktrans(x) insn_stack_block_transfers[(x >> 23) & 3] +#define op2_shift(x) op_shifts[(x >> 5) & 3] +#define insn_fparnd(x) insn_fpa_rounding[(x >> 5) & 0x03] +#define insn_fpaprec(x) insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1] +#define insn_fpaprect(x) insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1] +#define insn_fpaimm(x) insn_fpaconstants[x & 0x07] + +/* Local prototypes */ +static void disasm_register_shift(const disasm_interface_t *di, u_int insn); +static void disasm_print_reglist(const disasm_interface_t *di, u_int insn); +static void disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, + u_int loc); +static void disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, + u_int loc); +static void disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, + u_int loc); +static u_int disassemble_readword(u_int address); +static void disassemble_printaddr(u_int address); + +u_int +disasm(const disasm_interface_t *di, u_int loc, int altfmt) +{ + const struct arm32_insn *i_ptr = &arm32_i[0]; + + u_int insn; + int matchp; + int branch; + const char* f_ptr; + int fmt; + + fmt = 0; + matchp = 0; + insn = di->di_readword(loc); + +/* di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/ + + while (i_ptr->name) { + if ((insn & i_ptr->mask) == i_ptr->pattern) { + matchp = 1; + break; + } + i_ptr++; + } + + if (!matchp) { + di->di_printf("und%s\t%08x\n", insn_condition(insn), insn); + return(loc + INSN_SIZE); + } + + /* If instruction forces condition code, don't print it. */ + if ((i_ptr->mask & 0xf0000000) == 0xf0000000) + di->di_printf("%s", i_ptr->name); + else + di->di_printf("%s%s", i_ptr->name, insn_condition(insn)); + + f_ptr = i_ptr->format; + + /* Insert tab if there are no instruction modifiers */ + + if (*(f_ptr) < 'A' || *(f_ptr) > 'Z') { + ++fmt; + di->di_printf("\t"); + } + + while (*f_ptr) { + switch (*f_ptr) { + /* 2 - print Operand 2 of a data processing instruction */ + case '2': + if (insn & 0x02000000) { + int rotate= ((insn >> 7) & 0x1e); + + di->di_printf("#0x%08x", + (insn & 0xff) << (32 - rotate) | + (insn & 0xff) >> rotate); + } else { + disasm_register_shift(di, insn); + } + break; + /* d - destination register (bits 12-15) */ + case 'd': + di->di_printf("r%d", ((insn >> 12) & 0x0f)); + break; + /* D - insert 'p' if Rd is R15 */ + case 'D': + if (((insn >> 12) & 0x0f) == 15) + di->di_printf("p"); + break; + /* n - n register (bits 16-19) */ + case 'n': + di->di_printf("r%d", ((insn >> 16) & 0x0f)); + break; + /* s - s register (bits 8-11) */ + case 's': + di->di_printf("r%d", ((insn >> 8) & 0x0f)); + break; + /* o - indirect register rn (bits 16-19) (used by swap) */ + case 'o': + di->di_printf("[r%d]", ((insn >> 16) & 0x0f)); + break; + /* m - m register (bits 0-4) */ + case 'm': + di->di_printf("r%d", ((insn >> 0) & 0x0f)); + break; + /* a - address operand of ldr/str instruction */ + case 'a': + disasm_insn_ldrstr(di, insn, loc); + break; + /* e - address operand of ldrh/strh instruction */ + case 'e': + disasm_insn_ldrhstrh(di, insn, loc); + break; + /* l - register list for ldm/stm instruction */ + case 'l': + disasm_print_reglist(di, insn); + break; + /* f - 1st fp operand (register) (bits 12-14) */ + case 'f': + di->di_printf("f%d", (insn >> 12) & 7); + break; + /* g - 2nd fp operand (register) (bits 16-18) */ + case 'g': + di->di_printf("f%d", (insn >> 16) & 7); + break; + /* h - 3rd fp operand (register/immediate) (bits 0-4) */ + case 'h': + if (insn & (1 << 3)) + di->di_printf("#%s", insn_fpaimm(insn)); + else + di->di_printf("f%d", insn & 7); + break; + /* b - branch address */ + case 'b': + branch = ((insn << 2) & 0x03ffffff); + if (branch & 0x02000000) + branch |= 0xfc000000; + di->di_printaddr(loc + 8 + branch); + break; + /* t - blx address */ + case 't': + branch = ((insn << 2) & 0x03ffffff) | + (insn >> 23 & 0x00000002); + if (branch & 0x02000000) + branch |= 0xfc000000; + di->di_printaddr(loc + 8 + branch); + break; + /* X - block transfer type */ + case 'X': + di->di_printf("%s", insn_blktrans(insn)); + break; + /* Y - block transfer type (r13 base) */ + case 'Y': + di->di_printf("%s", insn_stkblktrans(insn)); + break; + /* c - comment field bits(0-23) */ + case 'c': + di->di_printf("0x%08x", (insn & 0x00ffffff)); + break; + /* k - breakpoint comment (bits 0-3, 8-19) */ + case 'k': + di->di_printf("0x%04x", + (insn & 0x000fff00) >> 4 | (insn & 0x0000000f)); + break; + /* p - saved or current status register */ + case 'p': + if (insn & 0x00400000) + di->di_printf("spsr"); + else + di->di_printf("cpsr"); + break; + /* F - PSR transfer fields */ + case 'F': + di->di_printf("_"); + if (insn & (1 << 16)) + di->di_printf("c"); + if (insn & (1 << 17)) + di->di_printf("x"); + if (insn & (1 << 18)) + di->di_printf("s"); + if (insn & (1 << 19)) + di->di_printf("f"); + break; + /* B - byte transfer flag */ + case 'B': + if (insn & 0x00400000) + di->di_printf("b"); + break; + /* L - co-processor transfer size */ + case 'L': + if (insn & (1 << 22)) + di->di_printf("l"); + break; + /* S - set status flag */ + case 'S': + if (insn & 0x00100000) + di->di_printf("s"); + break; + /* P - fp precision */ + case 'P': + di->di_printf("%s", insn_fpaprec(insn)); + break; + /* Q - fp precision (for ldf/stf) */ + case 'Q': + break; + /* R - fp rounding */ + case 'R': + di->di_printf("%s", insn_fparnd(insn)); + break; + /* W - writeback flag */ + case 'W': + if (insn & (1 << 21)) + di->di_printf("!"); + break; + /* # - co-processor number */ + case '#': + di->di_printf("p%d", (insn >> 8) & 0x0f); + break; + /* v - co-processor data transfer registers+addressing mode */ + case 'v': + disasm_insn_ldcstc(di, insn, loc); + break; + /* x - instruction in hex */ + case 'x': + di->di_printf("0x%08x", insn); + break; + /* y - co-processor data processing registers */ + case 'y': + di->di_printf("%d, ", (insn >> 20) & 0x0f); + + di->di_printf("c%d, c%d, c%d", (insn >> 12) & 0x0f, + (insn >> 16) & 0x0f, insn & 0x0f); + + di->di_printf(", %d", (insn >> 5) & 0x07); + break; + /* z - co-processor register transfer registers */ + case 'z': + di->di_printf("%d, ", (insn >> 21) & 0x07); + di->di_printf("r%d, c%d, c%d, %d", + (insn >> 12) & 0x0f, (insn >> 16) & 0x0f, + insn & 0x0f, (insn >> 5) & 0x07); + +/* if (((insn >> 5) & 0x07) != 0) + di->di_printf(", %d", (insn >> 5) & 0x07);*/ + break; + default: + di->di_printf("[%c - unknown]", *f_ptr); + break; + } + if (*(f_ptr+1) >= 'A' && *(f_ptr+1) <= 'Z') + ++f_ptr; + else if (*(++f_ptr)) { + ++fmt; + if (fmt == 1) + di->di_printf("\t"); + else + di->di_printf(", "); + } + }; + + di->di_printf("\n"); + + return(loc + INSN_SIZE); +} + + +static void +disasm_register_shift(const disasm_interface_t *di, u_int insn) +{ + di->di_printf("r%d", (insn & 0x0f)); + if ((insn & 0x00000ff0) == 0) + ; + else if ((insn & 0x00000ff0) == 0x00000060) + di->di_printf(", rrx"); + else { + if (insn & 0x10) + di->di_printf(", %s r%d", op2_shift(insn), + (insn >> 8) & 0x0f); + else + di->di_printf(", %s #%d", op2_shift(insn), + (insn >> 7) & 0x1f); + } +} + + +static void +disasm_print_reglist(const disasm_interface_t *di, u_int insn) +{ + int loop; + int start; + int comma; + + di->di_printf("{"); + start = -1; + comma = 0; + + for (loop = 0; loop < 17; ++loop) { + if (start != -1) { + if (loop == 16 || !(insn & (1 << loop))) { + if (comma) + di->di_printf(", "); + else + comma = 1; + if (start == loop - 1) + di->di_printf("r%d", start); + else + di->di_printf("r%d-r%d", start, loop - 1); + start = -1; + } + } else { + if (insn & (1 << loop)) + start = loop; + } + } + di->di_printf("}"); + + if (insn & (1 << 22)) + di->di_printf("^"); +} + +static void +disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, u_int loc) +{ + int offset; + + offset = insn & 0xfff; + if ((insn & 0x032f0000) == 0x010f0000) { + /* rA = pc, immediate index */ + if (insn & 0x00800000) + loc += offset; + else + loc -= offset; + di->di_printaddr(loc + 8); + } else { + di->di_printf("[r%d", (insn >> 16) & 0x0f); + if ((insn & 0x03000fff) != 0x01000000) { + di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]"); + if (!(insn & 0x00800000)) + di->di_printf("-"); + if (insn & (1 << 25)) + disasm_register_shift(di, insn); + else + di->di_printf("#0x%03x", offset); + } + if (insn & (1 << 24)) + di->di_printf("]"); + } +} + +static void +disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, u_int loc) +{ + int offset; + + offset = ((insn & 0xf00) >> 4) | (insn & 0xf); + if ((insn & 0x004f0000) == 0x004f0000) { + /* rA = pc, immediate index */ + if (insn & 0x00800000) + loc += offset; + else + loc -= offset; + di->di_printaddr(loc + 8); + } else { + di->di_printf("[r%d", (insn >> 16) & 0x0f); + if ((insn & 0x01400f0f) != 0x01400000) { + di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]"); + if (!(insn & 0x00800000)) + di->di_printf("-"); + if (insn & (1 << 22)) + di->di_printf("#0x%02x", offset); + else + di->di_printf("r%d", (insn & 0x0f)); + } + if (insn & (1 << 24)) + di->di_printf("]"); + } +} + +static void +disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int loc) +{ + if (((insn >> 8) & 0xf) == 1) + di->di_printf("f%d, ", (insn >> 12) & 0x07); + else + di->di_printf("c%d, ", (insn >> 12) & 0x0f); + + di->di_printf("[r%d", (insn >> 16) & 0x0f); + + di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]"); + + if (!(insn & (1 << 23))) + di->di_printf("-"); + + di->di_printf("#0x%03x", (insn & 0xff) << 2); + + if (insn & (1 << 24)) + di->di_printf("]"); + + if (insn & (1 << 21)) + di->di_printf("!"); +} + +static u_int +disassemble_readword(u_int address) +{ + return(*((u_int *)address)); +} + +static void +disassemble_printaddr(u_int address) +{ + printf("0x%08x", address); +} + +static void +disassemble_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +static const disasm_interface_t disassemble_di = { + disassemble_readword, disassemble_printaddr, disassemble_printf +}; + +void +disassemble(u_int address) +{ + + (void)disasm(&disassemble_di, address, 0); +} + +/* End of disassem.c */ diff --git a/libacc/tests/disassem.h b/libacc/tests/disassem.h new file mode 100644 index 00000000000..02747cd068f --- /dev/null +++ b/libacc/tests/disassem.h @@ -0,0 +1,65 @@ +/* $NetBSD: disassem.h,v 1.4 2001/03/04 04:15:58 matt Exp $ */ + +/*- + * Copyright (c) 1997 Mark Brinicombe. + * Copyright (c) 1997 Causality Limited. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Brinicombe. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Define the interface structure required by the disassembler. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/disassem.h,v 1.2 2005/01/05 21:58:48 imp Exp $ + */ + +#ifndef ANDROID_MACHINE_DISASSEM_H +#define ANDROID_MACHINE_DISASSEM_H + +#include + +#if __cplusplus +extern "C" { +#endif + +typedef struct { + u_int (*di_readword)(u_int); + void (*di_printaddr)(u_int); + void (*di_printf)(const char *, ...); +} disasm_interface_t; + +/* Prototypes for callable functions */ + +u_int disasm(const disasm_interface_t *, u_int, int); +void disassemble(u_int); + +#if __cplusplus +} +#endif + +#endif /* !ANDROID_MACHINE_DISASSEM_H */ diff --git a/libacc/tests/main.cpp b/libacc/tests/main.cpp new file mode 100644 index 00000000000..e4e386fc2b9 --- /dev/null +++ b/libacc/tests/main.cpp @@ -0,0 +1,207 @@ +/* + * Android "Almost" C Compiler. + * This is a compiler for a small subset of the C language, intended for use + * in scripting environments where speed and memory footprint are important. + * + * This code is based upon the "unobfuscated" version of the + * Obfuscated Tiny C compiler, see the file LICENSE for details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__arm__) +#include +#endif + +#if defined(__arm__) +#define PROVIDE_ARM_DISASSEMBLY +#endif + +#ifdef PROVIDE_ARM_DISASSEMBLY +#include "disassem.h" +#endif + +#include + + +typedef int (*MainPtr)(int, char**); +// This is a separate function so it can easily be set by breakpoint in gdb. +int run(MainPtr mainFunc, int argc, char** argv) { + return mainFunc(argc, argv); +} + +ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) { + return (ACCvoid*) dlsym(RTLD_DEFAULT, name); +} + +#ifdef PROVIDE_ARM_DISASSEMBLY + +static FILE* disasmOut; + +static u_int +disassemble_readword(u_int address) +{ + return(*((u_int *)address)); +} + +static void +disassemble_printaddr(u_int address) +{ + fprintf(disasmOut, "0x%08x", address); +} + +static void +disassemble_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(disasmOut, fmt, ap); + va_end(ap); +} + +static int disassemble(ACCscript* script, FILE* out) { + disasmOut = out; + disasm_interface_t di; + di.di_readword = disassemble_readword; + di.di_printaddr = disassemble_printaddr; + di.di_printf = disassemble_printf; + + ACCvoid* base; + ACCsizei length; + + accGetProgramBinary(script, &base, &length); + unsigned long* pBase = (unsigned long*) base; + unsigned long* pEnd = (unsigned long*) (((unsigned char*) base) + length); + + for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) { + fprintf(out, "%08x: %08x ", (int) pInstruction, (int) *pInstruction); + ::disasm(&di, (uint) pInstruction, 0); + } + return 0; +} + +#endif // PROVIDE_ARM_DISASSEMBLY + +int main(int argc, char** argv) { + const char* inFile = NULL; + bool printListing; + bool runResults = false; + FILE* in = stdin; + int i; + for (i = 1; i < argc; i++) { + char* arg = argv[i]; + if (arg[0] == '-') { + switch (arg[1]) { + case 'S': + printListing = true; + break; + case 'R': + runResults = true; + break; + default: + fprintf(stderr, "Unrecognized flag %s\n", arg); + return 3; + } + } else if (inFile == NULL) { + inFile = arg; + } else { + break; + } + } + + if (! inFile) { + fprintf(stderr, "input file required\n"); + return 2; + } + + if (inFile) { + in = fopen(inFile, "r"); + if (!in) { + fprintf(stderr, "Could not open input file %s\n", inFile); + return 1; + } + } + + fseek(in, 0, SEEK_END); + size_t fileSize = (size_t) ftell(in); + rewind(in); + ACCchar* text = new ACCchar[fileSize + 1]; + size_t bytesRead = fread(text, 1, fileSize, in); + if (bytesRead != fileSize) { + fprintf(stderr, "Could not read all of file %s\n", inFile); + } + + text[fileSize] = '\0'; + + ACCscript* script = accCreateScript(); + + const ACCchar* scriptSource[] = {text}; + accScriptSource(script, 1, scriptSource, NULL); + delete[] text; + + accRegisterSymbolCallback(script, symbolLookup, NULL); + + accCompileScript(script); + int result = accGetError(script); + MainPtr mainPointer = 0; + if (result != 0) { + ACCsizei bufferLength; + accGetScriptInfoLog(script, 0, &bufferLength, NULL); + char* buf = (char*) malloc(bufferLength + 1); + if (buf != NULL) { + accGetScriptInfoLog(script, bufferLength + 1, NULL, buf); + fprintf(stderr, "%s", buf); + free(buf); + } else { + fprintf(stderr, "Out of memory.\n"); + } + goto exit; + } + + { + ACCsizei numPragmaStrings; + accGetPragmas(script, &numPragmaStrings, 0, NULL); + if (numPragmaStrings) { + char** strings = new char*[numPragmaStrings]; + accGetPragmas(script, NULL, numPragmaStrings, strings); + for(ACCsizei i = 0; i < numPragmaStrings; i += 2) { + fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]); + } + delete[] strings; + } + } + + if (printListing) { +#ifdef PROVIDE_ARM_DISASSEMBLY + disassemble(script, stderr); +#endif + } + + if (runResults) { + accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer); + + result = accGetError(script); + if (result != ACC_NO_ERROR) { + fprintf(stderr, "Could not find main: %d\n", result); + } else { + fprintf(stderr, "Executing compiled code:\n"); + int codeArgc = argc - i + 1; + char** codeArgv = argv + i - 1; + codeArgv[0] = (char*) (inFile ? inFile : "stdin"); + result = run(mainPointer, codeArgc, codeArgv); + fprintf(stderr, "result: %d\n", result); + } + } + +exit: + + accDeleteScript(script); + + return result; +} diff --git a/libacc/tests/runtimeTest.cpp b/libacc/tests/runtimeTest.cpp new file mode 100644 index 00000000000..55bf877ed38 --- /dev/null +++ b/libacc/tests/runtimeTest.cpp @@ -0,0 +1,118 @@ +/* + * RuntimeTest for ACC compiler. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__arm__) +#include +#endif + +#include + + +typedef void (*ScriptPtr)(); + +// This is a separate function so it can easily be set by breakpoint in gdb. +void run(ScriptPtr scriptFn) { + scriptFn(); +} + +// Private API for development: + +extern "C" +void accDisassemble(ACCscript* script); + +int globalVar; + +void op_int(int a) { + printf("op_int(%d)\n", a); +} + +void op_float12(float a, float b, float c, float d, + float e, float f, float g, float h, + float i, float j, float k, float l) { + printf("op_float12(%g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g)\n", + a, b, c, d, e, f, g, h, i, j, k, l); +} + +const char* text = "void op_int(int a);\n" + "void op_float12(float a, float b, float c, float d,\n" + " float e, float f, float g, float h,\n" + " float i, float j, float k, float l);\n" + "void script() {\n" + " globalVar += 3;\n" + " op_int(123);\n" + " op_float12(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0);\n" + "}\n"; + +ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) { + if (strcmp("op_int", name) == 0) { + return (ACCvoid*) op_int; + } + if (strcmp("op_float12", name) == 0) { + return (ACCvoid*) op_float12; + } + if (strcmp("globalVar", name) == 0) { + return (ACCvoid*) &globalVar; + } + return (ACCvoid*) dlsym(RTLD_DEFAULT, name); +} + +int main(int argc, char** argv) { + ACCscript* script = accCreateScript(); + + accRegisterSymbolCallback(script, symbolLookup, NULL); + + const ACCchar* scriptSource[] = {text}; + accScriptSource(script, 1, scriptSource, NULL); + + accCompileScript(script); + int result = accGetError(script); + ScriptPtr scriptPointer = 0; + if (result != 0) { + char buf[1024]; + accGetScriptInfoLog(script, sizeof(buf), NULL, buf); + fprintf(stderr, "%s", buf); + goto exit; + } + + { + ACCsizei numPragmaStrings; + accGetPragmas(script, &numPragmaStrings, 0, NULL); + if (numPragmaStrings) { + char** strings = new char*[numPragmaStrings]; + accGetPragmas(script, NULL, numPragmaStrings, strings); + for(ACCsizei i = 0; i < numPragmaStrings; i += 2) { + fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]); + } + delete[] strings; + } + } + + accGetScriptLabel(script, "script", (ACCvoid**) & scriptPointer); + + result = accGetError(script); + if (result != ACC_NO_ERROR) { + fprintf(stderr, "Could not find script: %d\n", result); + } else { + fprintf(stderr, "Executing script:\n"); + globalVar = 17; + run(scriptPointer); + fprintf(stderr, "After script globalVar = %d\n", globalVar); + } + + +exit: + + accDeleteScript(script); + + return result; +} diff --git a/libacc/tests/test b/libacc/tests/test new file mode 100755 index 00000000000..8fd6916076c --- /dev/null +++ b/libacc/tests/test @@ -0,0 +1,6 @@ +#!/bin/bash + +SCRIPT_DIR=`dirname $BASH_SOURCE` +cd $SCRIPT_DIR +python test.py "$@" + diff --git a/libacc/tests/test.py b/libacc/tests/test.py new file mode 100644 index 00000000000..d9843011168 --- /dev/null +++ b/libacc/tests/test.py @@ -0,0 +1,493 @@ +# +# Test the acc compiler + +import unittest +import subprocess +import os +import sys + +gArmInitialized = False +gUseArm = True +gUseX86 = True +gRunOTCCOutput = True + + +def parseArgv(): + global gUseArm + global gUseX86 + global gRunOTCCOutput + for arg in sys.argv[1:]: + if arg == "--noarm": + print "--noarm: not testing ARM" + gUseArm = False + elif arg == "--nox86": + print "--nox86: not testing x86" + gUseX86 = False + elif arg == "--norunotcc": + print "--norunotcc detected, not running OTCC output" + gRunOTCCOutput = False + else: + print "Unknown parameter: ", arg + raise "Unknown parameter" + sys.argv = sys.argv[0:1] + +def compile(args): + proc = subprocess.Popen(["acc"] + args, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + result = proc.communicate() + return result + +def runCmd(args): + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = proc.communicate() + return result[0].strip() + +def uname(): + return runCmd(["uname"]) + +def unameM(): + return runCmd(["uname", "-m"]) + +def which(item): + return runCmd(["which", item]) + +def fileType(item): + return runCmd(["file", item]) + +def outputCanRun(): + ft = fileType(which("acc")) + return ft.find("ELF 32-bit LSB executable, Intel 80386") >= 0 + +def checkEnvironment(): + global gRunOTCCOutput + gRunOTCCOutput = uname() == "Linux" and unameM() != "x86_64" and outputCanRun() + +def adb(args): + return runCmd(["adb"] + args) + +def setupArm(): + global gArmInitialized + if gArmInitialized: + return + print "Setting up arm" + adb(["remount"]) + adb(["shell", "rm", "/system/bin/acc"]) + adb(["shell", "mkdir", "/system/bin/accdata"]) + adb(["shell", "mkdir", "/system/bin/accdata/data"]) + # Clear out old data TODO: handle recursion + adb(["shell", "rm", "/system/bin/accdata/data/*"]) + # Copy over data + for root, dirs, files in os.walk("data"): + for d in dirs: + adb(["shell", "mkdir", os.path.join(root, d)]) + for f in files: + adb(["push", os.path.join(root, f), os.path.join("/system/bin/accdata", root, f)]) + # Copy over compiler + adb(["sync"]) + gArmInitialized = True + +def compileArm(args): + setupArm() + proc = subprocess.Popen(["adb", "shell", "/system/bin/acc"] + args, stdout=subprocess.PIPE) + result = proc.communicate() + return result[0].replace("\r","") + +def compare(a, b): + if a != b: + firstDiff = firstDifference(a, b) + print "Strings differ at character %d. Common: %s. Difference '%s' != '%s'" % ( + firstDiff, a[0:firstDiff], safeAccess(a, firstDiff), safeAccess(b, firstDiff)) + +def safeAccess(s, i): + if 0 <= i < len(s): + return s[i] + else: + return '?' + +def firstDifference(a, b): + commonLen = min(len(a), len(b)) + for i in xrange(0, commonLen): + if a[i] != b[i]: + return i + return commonLen + +# a1 and a2 are the expected stdout and stderr. +# b1 and b2 are the actual stdout and stderr. +# Compare the two, sets. Allow any individual line +# to appear in either stdout or stderr. This is because +# the way we obtain output on the ARM combines both +# streams into one sequence. + +def compareOuput(a1,a2,b1,b2): + while True: + totalLen = len(a1) + len(a2) + len(b1) + len(b2) + a1, b1 = matchCommon(a1, b1) + a1, b2 = matchCommon(a1, b2) + a2, b1 = matchCommon(a2, b1) + a2, b2 = matchCommon(a2, b2) + newTotalLen = len(a1) + len(a2) + len(b1) + len(b2) + if newTotalLen == 0: + return True + if newTotalLen == totalLen: + print "Failed at %d %d %d %d" % (len(a1), len(a2), len(b1), len(b2)) + print "a1", a1 + print "a2", a2 + print "b1", b1 + print "b2", b2 + return False + +def matchCommon(a, b): + """Remove common items from the beginning of a and b, + return just the tails that are different.""" + while len(a) > 0 and len(b) > 0 and a[0] == b[0]: + a = a[1:] + b = b[1:] + return a, b + +def rewritePaths(args): + return [rewritePath(x) for x in args] + +def rewritePath(p): + """Take a path that's correct on the x86 and convert to a path + that's correct on ARM.""" + if p.startswith("data/"): + p = "/system/bin/accdata/" + p + return p + +class TestACC(unittest.TestCase): + + def checkResult(self, out, err, stdErrResult, stdOutResult=""): + a1 = out.splitlines() + a2 = err.splitlines() + b2 = stdErrResult.splitlines() + b1 = stdOutResult.splitlines() + self.assertEqual(True, compareOuput(a1,a2,b1,b2)) + + def compileCheck(self, args, stdErrResult, stdOutResult="", + targets=['arm', 'x86']): + global gUseArm + global gUseX86 + targetSet = frozenset(targets) + if gUseX86 and 'x86' in targetSet: + out, err = compile(args) + self.checkResult(out, err, stdErrResult, stdOutResult) + if gUseArm and 'arm' in targetSet: + out = compileArm(rewritePaths(args)) + self.checkResult(out, "", stdErrResult, stdOutResult) + + def compileCheckArm(self, args, result): + self.assertEqual(compileArm(args), result) + + def testCompileReturnVal(self): + self.compileCheck(["data/returnval-ansi.c"], "") + + def testCompileOTCCANSII(self): + self.compileCheck(["data/otcc-ansi.c"], "", "", ['x86']) + + def testRunReturnVal(self): + self.compileCheck(["-R", "data/returnval-ansi.c"], + "Executing compiled code:\nresult: 42\n") + + def testStringLiteralConcatenation(self): + self.compileCheck(["-R", "data/testStringConcat.c"], + "Executing compiled code:\nresult: 13\n", "Hello, world\n") + + def testRunOTCCANSI(self): + global gRunOTCCOutput + if gRunOTCCOutput: + self.compileCheck(["-R", "data/otcc-ansi.c", "data/returnval.c"], + "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\natcc-ansi.c: result: 42\nresult: 42\n", "", + ['x86']) + + def testRunOTCCANSI2(self): + global gRunOTCCOutput + if gRunOTCCOutput: + self.compileCheck(["-R", "data/otcc-ansi.c", "data/otcc.c", "data/returnval.c"], + "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\notcc.c: about to execute compiled code.\natcc-ansi.c: result: 42\nresult: 42\n", "",['x86']) + + def testRunConstants(self): + self.compileCheck(["-R", "data/constants.c"], + "Executing compiled code:\nresult: 12\n", + "0 = 0\n010 = 8\n0x10 = 16\n'\\a' = 7\n'\\b' = 8\n'\\f' = 12\n'\\n' = 10\n'\\r' = 13\n'\\t' = 9\n'\\v' = 11\n'\\\\' = 92\n'\\'' = 39\n" + + "'\\\"' = 34\n'\\?' = 63\n'\\0' = 0\n'\\1' = 1\n'\\12' = 10\n'\\123' = 83\n'\\x0' = 0\n'\\x1' = 1\n'\\x12' = 18\n'\\x123' = 291\n'\\x1f' = 31\n'\\x1F' = 31\n") + + def testRunFloat(self): + self.compileCheck(["-R", "data/float.c"], + "Executing compiled code:\nresult: 0\n", + """Constants: 0 0 0 0.01 0.01 0.1 10 10 0.1 +int: 1 float: 2.2 double: 3.3 + ftoi(1.4f)=1 + dtoi(2.4)=2 + itof(3)=3 + itod(4)=4 +globals: 1 2 3 4 +args: 1 2 3 4 +locals: 1 2 3 4 +cast rval: 2 4 +cast lval: 1.1 2 3.3 4 +""") + + def testRunFlops(self): + self.compileCheck(["-R", "data/flops.c"], + """Executing compiled code: +result: 0""", +"""-1.1 = -1.1 +!1.2 = 0 +!0 = 1 +double op double: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +float op float: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +double op float: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +double op int: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +int op double: +1 + 2 = 3 +1 - 2 = -1 +1 * 2 = 2 +1 / 2 = 0.5 +double op double: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +double op float: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +float op float: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +int op double: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +double op int: +1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 +1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 +2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 +branching: 1 0 1 +testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 +testpassidf: 1 2 3 +""") + def testCasts(self): + self.compileCheck(["-R", "data/casts.c"], + """Executing compiled code: +result: 0""", """Reading from a pointer: 3 3 +Writing to a pointer: 4 +Testing casts: 3 3 4.5 4 +Testing reading (int*): 4 +Testing writing (int*): 8 9 +Testing reading (char*): 0x78 0x56 0x34 0x12 +Testing writing (char*): 0x87654321 +f(10) +Function pointer result: 70 +Testing read/write (float*): 8.8 9.9 +Testing read/write (double*): 8.8 9.9 +""") + + def testChar(self): + self.compileCheck(["-R", "data/char.c"], """Executing compiled code: +result: 0""", """a = 99, b = 41 +ga = 100, gb = 44""") + + def testPointerArithmetic(self): + self.compileCheck(["-R", "data/pointers.c"], """Executing compiled code: +result: 0""", """Pointer difference: 1 4 +Pointer addition: 2 +Pointer comparison to zero: 0 0 1 +Pointer comparison: 1 0 0 0 1 +""") + def testRollo3(self): + self.compileCheck(["-R", "data/rollo3.c"], """Executing compiled code: +result: 10""", """""") + + def testFloatDouble(self): + self.compileCheck(["-R", "data/floatdouble.c"], """Executing compiled code: +result: 0""", """0.002 0.1 10""") + + def testIncDec(self): + self.compileCheck(["-R", "data/inc.c"], """Executing compiled code: +0 +1 +2 +1 +1 +2 +1 +0 +result: 0 +""","""""") + + def testIops(self): + self.compileCheck(["-R", "data/iops.c"], """Executing compiled code: +result: 0""", """Literals: 1 -1 +++ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +-- +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 +""") + + def testFilm(self): + self.compileCheck(["-R", "data/film.c"], """Executing compiled code: +result: 0""", """testing... +Total bad: 0 +""") + + def testpointers2(self): + self.compileCheck(["-R", "data/pointers2.c"], """Executing compiled code: +result: 0""", """a = 0, *pa = 0 +a = 2, *pa = 2 +a = 0, *pa = 0 **ppa = 0 +a = 2, *pa = 2 **ppa = 2 +a = 0, *pa = 0 **ppa = 0 +a = 2, *pa = 2 **ppa = 2 +""") + + def testassignmentop(self): + self.compileCheck(["-R", "data/assignmentop.c"], """Executing compiled code: +result: 0""", """2 *= 5 10 +20 /= 5 4 +17 %= 5 2 +17 += 5 22 +17 -= 5 12 +17<<= 1 34 +17>>= 1 8 +17&= 1 1 +17^= 1 16 +16|= 1 17 +*f() = *f() + 10; +f() +f() +a = 10 +*f() += 10; +f() +a = 10 +""") + + def testcomma(self): + self.compileCheck(["-R", "data/comma.c"], """Executing compiled code: +result: 0""", """statement: 10 +if: a = 0 +while: b = 11 +for: b = 22 +return: 30 +arg: 12 +""") + + def testBrackets(self): + self.compileCheck(["-R", "data/brackets.c"], """Executing compiled code: +Errors: 0 +2D Errors: 0 +result: 0 +""","""""") + + def testShort(self): + self.compileCheck(["-R", "data/short.c"], """Executing compiled code: +result: -2 +""","""""") + + def testAssignment(self): + self.compileCheck(["-R", "data/assignment.c"], """Executing compiled code: +result: 7 +""","""""") + + def testArray(self): + self.compileCheck(["-R", "data/array.c"], """Executing compiled code: +localInt: 3 +localDouble: 3 3 +globalChar: 3 +globalDouble: 3 +testArgs: 0 2 4 +testDecay: Hi! +test2D: +abcdefghijdefghijklm +defghijklmghijklmnop +ghijklmnopjklmnopabc +jklmnopabcmnopabcdef +mnopabcdefpabcdefghi +pabcdefghicdefghijkl +cdefghijklfghijklmno +fghijklmnoijklmnopab +ijklmnopablmnopabcde +lmnopabcdefghijklmno +result: 0 +""","""""") + + def testDefines(self): + self.compileCheck(["-R", "data/defines.c"], """Executing compiled code: +result: 3 +""","""""") + + def testFuncArgs(self): + self.compileCheck(["-R", "data/funcargs.c"], """Executing compiled code: +result: 4 +""","""""") + + def testB2071670(self): + self.compileCheck(["-R", "data/b2071670.c"], """Executing compiled code: +result: 1092616192 +""","""""") + + def testStructs(self): + self.compileCheck(["-R", "data/structs.c"], """Executing compiled code: +testCopying: 37 == 37 +testUnion: 1 == 0x3f800000 +testArgs: (6, 8, 10, 12) +result: 6 +""","""""") + + def testAddressOf(self): + self.compileCheck(["-R", "data/addressOf.c"], """Executing compiled code: +testStruct: 10 10 10 +testArray: 1 1 1 +result: 0 +""","""""") + +def main(): + checkEnvironment() + parseArgv() + unittest.main() + +if __name__ == '__main__': + main() + diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 18d0ee3180f..1d1e57603de 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -20,7 +20,7 @@ commonSources := \ array.c \ hashmap.c \ atomic.c \ - native_handle.c \ + native_handle.c \ buffer.c \ socket_inaddr_any_server.c \ socket_local_client.c \ @@ -36,40 +36,47 @@ commonSources := \ record_stream.c \ process_name.c \ properties.c \ - threads.c + threads.c \ + sched_policy.c + +commonHostSources := \ + ashmem-host.c # some files must not be compiled when building against Mingw # they correspond to features not used by our host development tools # which are also hard or even impossible to port to native Win32 -WITH_MINGW := +WINDOWS_HOST_ONLY := ifeq ($(HOST_OS),windows) ifeq ($(strip $(USE_CYGWIN)),) - WITH_MINGW := 1 + WINDOWS_HOST_ONLY := 1 endif endif # USE_MINGW is defined when we build against Mingw on Linux ifneq ($(strip $(USE_MINGW)),) - WITH_MINGW := 1 + WINDOWS_HOST_ONLY := 1 endif -ifeq ($(WITH_MINGW),1) +ifeq ($(WINDOWS_HOST_ONLY),1) commonSources += \ uio.c else commonSources += \ + abort_socket.c \ mspace.c \ selector.c \ tztime.c \ - tzstrftime.c \ adb_networking.c \ - zygote.c + zygote.c + + commonHostSources += \ + tzstrftime.c endif # Static library for host # ======================================================== LOCAL_MODULE := libcutils -LOCAL_SRC_FILES := $(commonSources) ashmem-host.c +LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) LOCAL_LDLIBS := -lpthread LOCAL_STATIC_LIBRARIES := liblog include $(BUILD_HOST_STATIC_LIBRARY) @@ -81,7 +88,7 @@ ifeq ($(TARGET_SIMULATOR),true) # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE := libcutils -LOCAL_SRC_FILES := $(commonSources) memory.c dlmalloc_stubs.c ashmem-host.c +LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) memory.c dlmalloc_stubs.c LOCAL_LDLIBS := -lpthread LOCAL_SHARED_LIBRARIES := liblog include $(BUILD_SHARED_LIBRARY) diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c new file mode 100644 index 00000000000..6a5e5e461fe --- /dev/null +++ b/libcutils/abort_socket.c @@ -0,0 +1,293 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "cutils/abort_socket.h" + +struct asocket *asocket_init(int fd) { + int abort_fd[2]; + int flags; + struct asocket *s; + + /* set primary socket to non-blocking */ + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return NULL; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) + return NULL; + + /* create pipe with non-blocking write, so that asocket_close() cannot + block */ + if (pipe(abort_fd)) + return NULL; + flags = fcntl(abort_fd[1], F_GETFL); + if (flags == -1) + return NULL; + if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK)) + return NULL; + + s = malloc(sizeof(struct asocket)); + if (!s) + return NULL; + + s->fd = fd; + s->abort_fd[0] = abort_fd[0]; + s->abort_fd[1] = abort_fd[1]; + + return s; +} + +int asocket_connect(struct asocket *s, const struct sockaddr *addr, + socklen_t addrlen, int timeout) { + + int ret; + + do { + ret = connect(s->fd, addr, addrlen); + } while (ret && errno == EINTR); + + if (ret && errno == EINPROGRESS) { + /* ready to poll() */ + socklen_t retlen; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLOUT; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLOUT) { + /* connect call complete, read return code */ + retlen = sizeof(ret); + if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen)) + return -1; + /* got connect() return code */ + if (ret) { + errno = ret; + } + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + } + + return ret; +} + +int asocket_accept(struct asocket *s, struct sockaddr *addr, + socklen_t *addrlen, int timeout) { + + int ret; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLIN) { + /* ready to accept() without blocking */ + do { + ret = accept(s->fd, addr, addrlen); + } while (ret < 0 && errno == EINTR); + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + + return ret; +} + +int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) { + int ret; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLIN) { + /* ready to read() without blocking */ + do { + ret = read(s->fd, buf, count); + } while (ret < 0 && errno == EINTR); + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + + return ret; +} + +int asocket_write(struct asocket *s, const void *buf, size_t count, + int timeout) { + int ret; + struct pollfd pfd[2]; + + pfd[0].fd = s->fd; + pfd[0].events = POLLOUT; + pfd[0].revents = 0; + pfd[1].fd = s->abort_fd[0]; + pfd[1].events = POLLIN; + pfd[1].revents = 0; + + do { + ret = poll(pfd, 2, timeout); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) + return -1; + else if (ret == 0) { + /* timeout */ + errno = ETIMEDOUT; + return -1; + } + + if (pfd[1].revents) { + /* abort due to asocket_abort() */ + errno = ECANCELED; + return -1; + } + + if (pfd[0].revents) { + if (pfd[0].revents & POLLOUT) { + /* ready to write() without blocking */ + do { + ret = write(s->fd, buf, count); + } while (ret < 0 && errno == EINTR); + } else { + /* some error event on this fd */ + errno = ECONNABORTED; + return -1; + } + } + + return ret; +} + +void asocket_abort(struct asocket *s) { + int ret; + char buf = 0; + + /* Prevent further use of fd, without yet releasing the fd */ + shutdown(s->fd, SHUT_RDWR); + + /* wake up calls blocked at poll() */ + do { + ret = write(s->abort_fd[1], &buf, 1); + } while (ret < 0 && errno == EINTR); +} + +void asocket_destroy(struct asocket *s) { + struct asocket s_copy = *s; + + /* Clients should *not* be using these fd's after calling + asocket_destroy(), but in case they do, set to -1 so they cannot use a + stale fd */ + s->fd = -1; + s->abort_fd[0] = -1; + s->abort_fd[1] = -1; + + /* Call asocket_abort() in case there are still threads blocked on this + socket. Clients should not rely on this behavior - it is racy because we + are about to close() these sockets - clients should instead make sure + all threads are done with the socket before calling asocket_destory(). + */ + asocket_abort(&s_copy); + + /* enough safety checks, close and release memory */ + close(s_copy.abort_fd[1]); + close(s_copy.abort_fd[0]); + close(s_copy.fd); + + free(s); +} diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S index c56ec5d0e32..7befd780268 100644 --- a/libcutils/atomic-android-arm.S +++ b/libcutils/atomic-android-arm.S @@ -55,23 +55,8 @@ */ android_atomic_write: - stmdb sp!, {r4, lr} - mov r2, r1 - mov r1, r0 -1: @ android_atomic_write - ldr r0, [r2] - mov r3, #kernel_atomic_base -#ifdef __ARM_HAVE_PC_INTERWORK - add lr, pc, #4 - add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) -#else - add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) - mov lr, pc - bx r3 -#endif - bcc 1b - ldmia sp!, {r4, lr} - bx lr + str r0, [r1] + bx lr; /* * ---------------------------------------------------------------------------- @@ -81,6 +66,8 @@ android_atomic_write: */ android_atomic_inc: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r2, r0 1: @ android_atomic_inc @@ -100,6 +87,7 @@ android_atomic_inc: sub r0, r1, #1 ldmia sp!, {r4, lr} bx lr + .fnend /* * ---------------------------------------------------------------------------- @@ -109,6 +97,8 @@ android_atomic_inc: */ android_atomic_dec: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r2, r0 1: @ android_atomic_dec @@ -128,6 +118,7 @@ android_atomic_dec: add r0, r1, #1 ldmia sp!, {r4, lr} bx lr + .fnend /* * ---------------------------------------------------------------------------- @@ -137,6 +128,8 @@ android_atomic_dec: */ android_atomic_add: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r2, r1 mov r4, r0 @@ -157,6 +150,7 @@ android_atomic_add: sub r0, r1, r4 ldmia sp!, {r4, lr} bx lr + .fnend /* @@ -167,6 +161,8 @@ android_atomic_add: */ android_atomic_and: + .fnstart + .save {r4, r5, lr} stmdb sp!, {r4, r5, lr} mov r2, r1 /* r2 = address */ mov r4, r0 /* r4 = the value */ @@ -189,6 +185,7 @@ android_atomic_and: mov r0, r5 ldmia sp!, {r4, r5, lr} bx lr + .fnend /* * ---------------------------------------------------------------------------- @@ -198,6 +195,8 @@ android_atomic_and: */ android_atomic_or: + .fnstart + .save {r4, r5, lr} stmdb sp!, {r4, r5, lr} mov r2, r1 /* r2 = address */ mov r4, r0 /* r4 = the value */ @@ -220,6 +219,7 @@ android_atomic_or: mov r0, r5 ldmia sp!, {r4, r5, lr} bx lr + .fnend /* * ---------------------------------------------------------------------------- @@ -243,6 +243,8 @@ android_atomic_swap: */ android_atomic_cmpxchg: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r4, r0 /* r4 = save oldvalue */ 1: @ android_atomic_cmpxchg @@ -264,6 +266,7 @@ android_atomic_cmpxchg: 2: @ android_atomic_cmpxchg ldmia sp!, {r4, lr} bx lr + .fnend /* * ---------------------------------------------------------------------------- diff --git a/libcutils/atomic-android-armv6.S b/libcutils/atomic-android-armv6.S index 64146c17795..a71308966c9 100644 --- a/libcutils/atomic-android-armv6.S +++ b/libcutils/atomic-android-armv6.S @@ -45,11 +45,8 @@ */ android_atomic_write: -1: ldrex r12, [r1] - strex r12, r0, [r1] - cmp r12, #0 - bne 1b - bx lr + str r0, [r1] + bx lr; /* * ---------------------------------------------------------------------------- diff --git a/libcutils/process_name.c b/libcutils/process_name.c index 17f52e2698b..b235429d01d 100644 --- a/libcutils/process_name.c +++ b/libcutils/process_name.c @@ -22,6 +22,10 @@ #include #include +#if defined(HAVE_PRCTL) +#include +#endif + #define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name" static const char* process_name = "unknown"; @@ -35,10 +39,19 @@ void set_process_name(const char* new_name) { } // We never free the old name. Someone else could be using it. - char* copy = (char*) malloc(strlen(new_name) + 1); + int len = strlen(new_name); + char* copy = (char*) malloc(len + 1); strcpy(copy, new_name); process_name = (const char*) copy; +#if defined(HAVE_PRCTL) + if (len < 16) { + prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0); + } else { + prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0); + } +#endif + // If we know we are not running in the emulator, then return. if (running_in_emulator == 0) { return; diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c new file mode 100644 index 00000000000..64d9bb71a15 --- /dev/null +++ b/libcutils/sched_policy.c @@ -0,0 +1,221 @@ + +/* libs/cutils/sched_policy.c +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "SchedPolicy" +#include "cutils/log.h" + +#ifdef HAVE_SCHED_H + +#include + +#include + +#ifndef SCHED_NORMAL + #define SCHED_NORMAL 0 +#endif + +#ifndef SCHED_BATCH + #define SCHED_BATCH 3 +#endif + +#define POLICY_DEBUG 0 + +static int __sys_supports_schedgroups = -1; + +static int add_tid_to_cgroup(int tid, const char *grp_name) +{ + int fd; + char path[255]; + char text[64]; + + sprintf(path, "/dev/cpuctl/%s/tasks", grp_name); + + if ((fd = open(path, O_WRONLY)) < 0) { + LOGE("add_tid_to_cgroup failed to open '%s' (%s)\n", path, strerror(errno)); + return -1; + } + + sprintf(text, "%d", tid); + if (write(fd, text, strlen(text)) < 0) { + close(fd); + return -1; + } + + close(fd); + return 0; +} + +static inline void initialize() +{ + if (__sys_supports_schedgroups < 0) { + if (!access("/dev/cpuctl/tasks", F_OK)) { + __sys_supports_schedgroups = 1; + } else { + __sys_supports_schedgroups = 0; + } + } +} + +/* + * Try to get the scheduler group. + * + * The data from /proc//cgroup looks like: + * 2:cpu:/bg_non_interactive + * + * We return the part after the "/", which will be an empty string for + * the default cgroup. If the string is longer than "bufLen", the string + * will be truncated. + */ +static int getSchedulerGroup(int tid, char* buf, size_t bufLen) +{ +#ifdef HAVE_ANDROID_OS + char pathBuf[32]; + char readBuf[256]; + ssize_t count; + int fd; + + snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid); + if ((fd = open(pathBuf, O_RDONLY)) < 0) { + return -1; + } + + count = read(fd, readBuf, sizeof(readBuf)); + if (count <= 0) { + close(fd); + errno = ENODATA; + return -1; + } + close(fd); + + readBuf[--count] = '\0'; /* remove the '\n', now count==strlen */ + + char* cp = strchr(readBuf, '/'); + if (cp == NULL) { + readBuf[sizeof(readBuf)-1] = '\0'; + errno = ENODATA; + return -1; + } + + memcpy(buf, cp+1, count); /* count-1 for cp+1, count+1 for NUL */ + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +int get_sched_policy(int tid, SchedPolicy *policy) +{ + initialize(); + + if (__sys_supports_schedgroups) { + char grpBuf[32]; + if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0) + return -1; + if (grpBuf[0] == '\0') { + *policy = SP_FOREGROUND; + } else if (!strcmp(grpBuf, "bg_non_interactive")) { + *policy = SP_BACKGROUND; + } else { + errno = ERANGE; + return -1; + } + } else { + int rc = sched_getscheduler(tid); + if (rc < 0) + return -1; + else if (rc == SCHED_NORMAL) + *policy = SP_FOREGROUND; + else if (rc == SCHED_BATCH) + *policy = SP_BACKGROUND; + else { + errno = ERANGE; + return -1; + } + } + return 0; +} + +int set_sched_policy(int tid, SchedPolicy policy) +{ + initialize(); + +#if POLICY_DEBUG + char statfile[64]; + char statline[1024]; + char thread_name[255]; + int fd; + + sprintf(statfile, "/proc/%d/stat", tid); + memset(thread_name, 0, sizeof(thread_name)); + + fd = open(statfile, O_RDONLY); + if (fd >= 0) { + int rc = read(fd, statline, 1023); + close(fd); + statline[rc] = 0; + char *p = statline; + char *q; + + for (p = statline; *p != '('; p++); + p++; + for (q = p; *q != ')'; q++); + + strncpy(thread_name, p, (q-p)); + } + if (policy == SP_BACKGROUND) { + LOGD("vvv tid %d (%s)", tid, thread_name); + } else if (policy == SP_FOREGROUND) { + LOGD("^^^ tid %d (%s)", tid, thread_name); + } else { + LOGD("??? tid %d (%s)", tid, thread_name); + } +#endif + + if (__sys_supports_schedgroups) { + const char *grp = ""; + + if (policy == SP_BACKGROUND) { + grp = "bg_non_interactive"; + } + + if (add_tid_to_cgroup(tid, grp)) { + if (errno != ESRCH && errno != ENOENT) + return -errno; + } + } else { + struct sched_param param; + + param.sched_priority = 0; + sched_setscheduler(tid, + (policy == SP_BACKGROUND) ? + SCHED_BATCH : SCHED_NORMAL, + ¶m); + } + + return 0; +} + +#endif /* HAVE_SCHED_H */ diff --git a/libcutils/strdup16to8.c b/libcutils/strdup16to8.c index fadaabed8e0..1a8ba867436 100644 --- a/libcutils/strdup16to8.c +++ b/libcutils/strdup16to8.c @@ -15,6 +15,8 @@ ** limitations under the License. */ +#include /* for SIZE_MAX */ + #include #include #include @@ -26,19 +28,67 @@ */ extern size_t strnlen16to8(const char16_t* utf16Str, size_t len) { - size_t utf8Len = 0; - - while (len--) { - unsigned int uic = *utf16Str++; - - if (uic > 0x07ff) - utf8Len += 3; - else if (uic > 0x7f || uic == 0) - utf8Len += 2; - else - utf8Len++; - } - return utf8Len; + size_t utf8Len = 0; + + /* A small note on integer overflow. The result can + * potentially be as big as 3*len, which will overflow + * for len > SIZE_MAX/3. + * + * Moreover, the result of a strnlen16to8 is typically used + * to allocate a destination buffer to strncpy16to8 which + * requires one more byte to terminate the UTF-8 copy, and + * this is generally done by careless users by incrementing + * the result without checking for integer overflows, e.g.: + * + * dst = malloc(strnlen16to8(utf16,len)+1) + * + * Due to this, the following code will try to detect + * overflows, and never return more than (SIZE_MAX-1) + * when it detects one. A careless user will try to malloc + * SIZE_MAX bytes, which will return NULL which can at least + * be detected appropriately. + * + * As far as I know, this function is only used by strndup16(), + * but better be safe than sorry. + */ + + /* Fast path for the usual case where 3*len is < SIZE_MAX-1. + */ + if (len < (SIZE_MAX-1)/3) { + while (len--) { + unsigned int uic = *utf16Str++; + + if (uic > 0x07ff) + utf8Len += 3; + else if (uic > 0x7f || uic == 0) + utf8Len += 2; + else + utf8Len++; + } + return utf8Len; + } + + /* The slower but paranoid version */ + while (len--) { + unsigned int uic = *utf16Str++; + size_t utf8Cur = utf8Len; + + if (uic > 0x07ff) + utf8Len += 3; + else if (uic > 0x7f || uic == 0) + utf8Len += 2; + else + utf8Len++; + + if (utf8Len < utf8Cur) /* overflow detected */ + return SIZE_MAX-1; + } + + /* don't return SIZE_MAX to avoid common user bug */ + if (utf8Len == SIZE_MAX) + utf8Len = SIZE_MAX-1; + + return utf8Len; } @@ -50,7 +100,7 @@ extern size_t strnlen16to8(const char16_t* utf16Str, size_t len) * * Make sure you allocate "utf8Str" with the result of strlen16to8() + 1, * not just "len". - * + * * Please note, a terminated \0 is always added, so your result will always * be "strlen16to8() + 1" bytes long. */ @@ -58,6 +108,10 @@ extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len) { char* utf8cur = utf8Str; + /* Note on overflows: We assume the user did check the result of + * strnlen16to8() properly or at a minimum checked the result of + * its malloc(SIZE_MAX) in case of overflow. + */ while (len--) { unsigned int uic = *utf16Str++; @@ -73,8 +127,8 @@ extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len) if (uic == 0) { break; - } - } + } + } } *utf8cur = '\0'; @@ -85,20 +139,30 @@ extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len) /** * Convert a UTF-16 string to UTF-8. * - * Make sure you allocate "dest" with the result of strblen16to8(), - * not just "strlen16()". */ char * strndup16to8 (const char16_t* s, size_t n) { - char *ret; + char* ret; + size_t len; if (s == NULL) { return NULL; } - ret = malloc(strnlen16to8(s, n) + 1); + len = strnlen16to8(s, n); + + /* We are paranoid, and we check for SIZE_MAX-1 + * too since it is an overflow value for our + * strnlen16to8 implementation. + */ + if (len >= SIZE_MAX-1) + return NULL; + + ret = malloc(len + 1); + if (ret == NULL) + return NULL; strncpy16to8 (ret, s, n); - - return ret; + + return ret; } diff --git a/libcutils/tztime.c b/libcutils/tztime.c index 93bbb29da1a..d6448a1dad9 100644 --- a/libcutils/tztime.c +++ b/libcutils/tztime.c @@ -53,6 +53,31 @@ static char elsieid[] = "@(#)localtime.c 8.3"; #define OPEN_MODE O_RDONLY #endif /* !defined O_BINARY */ +/* Complex computations to determine the min/max of time_t depending + * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL. + * These macros cannot be used in pre-processor directives, so we + * let the C compiler do the work, which makes things a bit funky. + */ +static const time_t TIME_T_MAX = + TYPE_INTEGRAL(time_t) ? + ( TYPE_SIGNED(time_t) ? + ~((time_t)1 << (TYPE_BIT(time_t)-1)) + : + ~(time_t)0 + ) + : /* if time_t is a floating point number */ + ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX ); + +static const time_t TIME_T_MIN = + TYPE_INTEGRAL(time_t) ? + ( TYPE_SIGNED(time_t) ? + ((time_t)1 << (TYPE_BIT(time_t)-1)) + : + 0 + ) + : + ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN ); + #ifndef WILDABBR /* ** Someone might make incorrect use of a time zone abbreviation: @@ -158,7 +183,7 @@ static void gmtload P((struct state * sp)); static struct tm * gmtsub P((const time_t * timep, long offset, struct tm * tmp)); static struct tm * localsub P((const time_t * timep, long offset, - struct tm * tmp, struct state *sp)); + struct tm * tmp, const struct state *sp)); static int increment_overflow P((int * number, int delta)); static int leaps_thru_end_of P((int y)); static int long_increment_overflow P((long * number, int delta)); @@ -1157,7 +1182,7 @@ localsub(timep, offset, tmp, sp) const time_t * const timep; const long offset; struct tm * const tmp; -struct state * sp; +const struct state * sp; { register const struct ttinfo * ttisp; register int i; @@ -1553,26 +1578,36 @@ char * buf; static int increment_overflow(number, delta) -int * number; -int delta; +int * number; +int delta; { - int number0; + unsigned number0 = (unsigned)*number; + unsigned number1 = (unsigned)(number0 + delta); + + *number = (int)number1; - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); + if (delta >= 0) { + return ((int)number1 < (int)number0); + } else { + return ((int)number1 > (int)number0); + } } static int long_increment_overflow(number, delta) -long * number; -int delta; +long * number; +int delta; { - long number0; + unsigned long number0 = (unsigned long)*number; + unsigned long number1 = (unsigned long)(number0 + delta); - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); + *number = (long)number1; + + if (delta >= 0) { + return ((long)number1 < (long)number0); + } else { + return ((long)number1 > (long)number0); + } } static int @@ -1741,14 +1776,14 @@ const struct state * sp; } else dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (t == lo) { + if (t == TIME_T_MAX) + return WRONG; ++t; - if (t <= lo) - return WRONG; ++lo; } else if (t == hi) { + if (t == TIME_T_MIN) + return WRONG; --t; - if (t >= hi) - return WRONG; --hi; } if (lo > hi) diff --git a/liblog/logd_write.c b/liblog/logd_write.c index 96da38b6c2f..241dbf0c72c 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -142,11 +142,7 @@ int __android_log_write(int prio, const char *tag, const char *msg) /* XXX: This needs to go! */ if (!strcmp(tag, "HTC_RIL") || - !strcmp(tag, "RILJ") || - !strcmp(tag, "RILB") || - !strcmp(tag, "RILC") || - !strcmp(tag, "RILD") || - !strcmp(tag, "RIL") || + !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ !strcmp(tag, "AT") || !strcmp(tag, "GSM") || !strcmp(tag, "STK") || diff --git a/liblog/logprint.c b/liblog/logprint.c index 2cf12545f16..080f9e364e4 100644 --- a/liblog/logprint.c +++ b/liblog/logprint.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c index d6120dae3c1..e089d791fbd 100644 --- a/libmincrypt/sha.c +++ b/libmincrypt/sha.c @@ -13,20 +13,183 @@ ** be used to endorse or promote products derived from this software ** without specific prior written permission. ** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR +** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mincrypt/sha.h" +// Some machines lack byteswap.h and endian.h. These have to use the +// slower code, even if they're little-endian. + +#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) + +#include +#include + +// This version is about 28% faster than the generic version below, +// but assumes little-endianness. + +static inline uint32_t ror27(uint32_t val) { + return (val >> 27) | (val << 5); +} +static inline uint32_t ror2(uint32_t val) { + return (val >> 2) | (val << 30); +} +static inline uint32_t ror31(uint32_t val) { + return (val >> 31) | (val << 1); +} + +static void SHA1_Transform(SHA_CTX* ctx) { + uint32_t W[80]; + register uint32_t A, B, C, D, E; + int t; + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define SHA_F1(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = bswap_32(ctx->buf.w[t])) + \ + (D^(B&(C^D))) + 0x5A827999; \ + B = ror2(B); + + for (t = 0; t < 15; t += 5) { + SHA_F1(A,B,C,D,E,t + 0); + SHA_F1(E,A,B,C,D,t + 1); + SHA_F1(D,E,A,B,C,t + 2); + SHA_F1(C,D,E,A,B,t + 3); + SHA_F1(B,C,D,E,A,t + 4); + } + SHA_F1(A,B,C,D,E,t + 0); // 16th one, t == 15 + +#undef SHA_F1 + +#define SHA_F1(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + (D^(B&(C^D))) + 0x5A827999; \ + B = ror2(B); + + SHA_F1(E,A,B,C,D,t + 1); + SHA_F1(D,E,A,B,C,t + 2); + SHA_F1(C,D,E,A,B,t + 3); + SHA_F1(B,C,D,E,A,t + 4); + +#undef SHA_F1 + +#define SHA_F2(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + (B^C^D) + 0x6ED9EBA1; \ + B = ror2(B); + + for (t = 20; t < 40; t += 5) { + SHA_F2(A,B,C,D,E,t + 0); + SHA_F2(E,A,B,C,D,t + 1); + SHA_F2(D,E,A,B,C,t + 2); + SHA_F2(C,D,E,A,B,t + 3); + SHA_F2(B,C,D,E,A,t + 4); + } + +#undef SHA_F2 + +#define SHA_F3(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + ((B&C)|(D&(B|C))) + 0x8F1BBCDC; \ + B = ror2(B); + + for (; t < 60; t += 5) { + SHA_F3(A,B,C,D,E,t + 0); + SHA_F3(E,A,B,C,D,t + 1); + SHA_F3(D,E,A,B,C,t + 2); + SHA_F3(C,D,E,A,B,t + 3); + SHA_F3(B,C,D,E,A,t + 4); + } + +#undef SHA_F3 + +#define SHA_F4(A,B,C,D,E,t) \ + E += ror27(A) + \ + (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \ + (B^C^D) + 0xCA62C1D6; \ + B = ror2(B); + + for (; t < 80; t += 5) { + SHA_F4(A,B,C,D,E,t + 0); + SHA_F4(E,A,B,C,D,t + 1); + SHA_F4(D,E,A,B,C,t + 2); + SHA_F4(C,D,E,A,B,t + 3); + SHA_F4(B,C,D,E,A,t + 4); + } + +#undef SHA_F4 + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +void SHA_update(SHA_CTX* ctx, const void* data, int len) { + int i = ctx->count % sizeof(ctx->buf); + const uint8_t* p = (const uint8_t*)data; + + ctx->count += len; + + while (len > sizeof(ctx->buf) - i) { + memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i); + len -= sizeof(ctx->buf) - i; + p += sizeof(ctx->buf) - i; + SHA1_Transform(ctx); + i = 0; + } + + while (len--) { + ctx->buf.b[i++] = *p++; + if (i == sizeof(ctx->buf)) { + SHA1_Transform(ctx); + i = 0; + } + } +} + + +const uint8_t* SHA_final(SHA_CTX* ctx) { + uint64_t cnt = ctx->count * 8; + int i; + + SHA_update(ctx, (uint8_t*)"\x80", 1); + while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) { + SHA_update(ctx, (uint8_t*)"\0", 1); + } + for (i = 0; i < 8; ++i) { + uint8_t tmp = cnt >> ((7 - i) * 8); + SHA_update(ctx, &tmp, 1); + } + + for (i = 0; i < 5; i++) { + ctx->buf.w[i] = bswap_32(ctx->state[i]); + } + + return ctx->buf.b; +} + +#else // #if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN) + #define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits)))) static void SHA1_transform(SHA_CTX *ctx) { @@ -79,15 +242,6 @@ static void SHA1_transform(SHA_CTX *ctx) { ctx->state[4] += E; } -void SHA_init(SHA_CTX *ctx) { - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; - ctx->state[4] = 0xC3D2E1F0; - ctx->count = 0; -} - void SHA_update(SHA_CTX *ctx, const void *data, int len) { int i = ctx->count % sizeof(ctx->buf); const uint8_t* p = (const uint8_t*)data; @@ -127,6 +281,17 @@ const uint8_t *SHA_final(SHA_CTX *ctx) { return ctx->buf; } +#endif // endianness + +void SHA_init(SHA_CTX* ctx) { + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->count = 0; +} + /* Convenience function */ const uint8_t* SHA(const void *data, int len, uint8_t *digest) { const uint8_t *p; diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index 88635d96943..bde336f6a58 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -224,6 +224,16 @@ int ifc_add_host_route(const char *name, in_addr_t addr) return result; } +int ifc_enable(const char *ifname) +{ + int result; + + ifc_init(); + result = ifc_up(ifname); + ifc_close(); + return result; +} + int ifc_disable(const char *ifname) { int result; diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk index 50eb5f5d58f..0cc85d9dcc3 100644 --- a/libpixelflinger/Android.mk +++ b/libpixelflinger/Android.mk @@ -64,12 +64,14 @@ endif LOCAL_MODULE:= libpixelflinger LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES) LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS) + ifneq ($(BUILD_TINY_ANDROID),true) # Really this should go away entirely or at least not depend on # libhardware, but this at least gets us built. LOCAL_SHARED_LIBRARIES += libhardware_legacy LOCAL_CFLAGS += -DWITH_LIB_HARDWARE endif + ifeq ($(TARGET_ARCH),arm) LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6 endif diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp index f10217b74a7..083042ce9d4 100644 --- a/libpixelflinger/codeflinger/blending.cpp +++ b/libpixelflinger/codeflinger/blending.cpp @@ -221,17 +221,7 @@ void GGLAssembler::build_blending( build_blend_factor(dst_factor, fd, component, pixel, fragment, fb, scratches); mul_factor_add(temp, fb, dst_factor, component_t(fragment)); - if (fd==GGL_ONE_MINUS_SRC_ALPHA) { - // XXX: in theory this is not correct, we should - // saturate here. However, this mode is often - // used for displaying alpha-premultiplied graphics, - // in which case, saturation is not necessary. - // unfortunatelly, we have no way to know. - // This is a case, where we sacrifice correctness for - // performance. we should probably have some heuristics. - } else { - component_sat(temp); - } + component_sat(temp); } } else { // compute fs diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S index d4b257981aa..caf9eb7cdbf 100644 --- a/libpixelflinger/t32cb16blend.S +++ b/libpixelflinger/t32cb16blend.S @@ -21,53 +21,80 @@ .global scanline_t32cb16blend_arm -// uses r6, r7, lr -.macro pixel, DREG, SRC, FB, OFFSET - - // SRC = AARRGGBB +/* + * .macro pixel + * + * \DREG is a 32-bit register containing *two* original destination RGB565 + * pixels, with the even one in the low-16 bits, and the odd one in the + * high 16 bits. + * + * \SRC is a 32-bit 0xAABBGGRR pixel value, with pre-multiplied colors. + * + * \FB is a target register that will contain the blended pixel values. + * + * \ODD is either 0 or 1 and indicates if we're blending the lower or + * upper 16-bit pixels in DREG into FB + * + * + * clobbered: r6, r7, lr + * + */ + +.macro pixel, DREG, SRC, FB, ODD + + // SRC = 0xAABBGGRR mov r7, \SRC, lsr #24 // sA add r7, r7, r7, lsr #7 // sA + (sA >> 7) rsb r7, r7, #0x100 // sA = 0x100 - (sA+(sA>>7)) 1: -.if \OFFSET +.if \ODD // red - mov lr, \DREG, lsr #(\OFFSET + 6 + 5) + mov lr, \DREG, lsr #(16 + 11) smulbb lr, r7, lr mov r6, \SRC, lsr #3 and r6, r6, #0x1F add lr, r6, lr, lsr #8 - orr \FB, lr, lsl #(\OFFSET + 11) + cmp lr, #0x1F + orrhs \FB, \FB, #(0x1F<<(16 + 11)) + orrlo \FB, \FB, lr, lsl #(16 + 11) // green - and r6, \DREG, #(0x3F<<(\OFFSET + 5)) + and r6, \DREG, #(0x3F<<(16 + 5)) smulbt r6, r7, r6 mov lr, \SRC, lsr #(8+2) and lr, lr, #0x3F add r6, lr, r6, lsr #(5+8) - orr \FB, \FB, r6, lsl #(\OFFSET + 5) + cmp r6, #0x3F + orrhs \FB, \FB, #(0x3F<<(16 + 5)) + orrlo \FB, \FB, r6, lsl #(16 + 5) // blue - and lr, \DREG, #(0x1F << \OFFSET) + and lr, \DREG, #(0x1F << 16) smulbt lr, r7, lr mov r6, \SRC, lsr #(8+8+3) and r6, r6, #0x1F add lr, r6, lr, lsr #8 - orr \FB, \FB, lr, lsl #\OFFSET + cmp lr, #0x1F + orrhs \FB, \FB, #(0x1F << 16) + orrlo \FB, \FB, lr, lsl #16 .else // red - mov lr, \DREG, lsr #(6+5) + mov lr, \DREG, lsr #11 and lr, lr, #0x1F smulbb lr, r7, lr mov r6, \SRC, lsr #3 and r6, r6, #0x1F add lr, r6, lr, lsr #8 - mov \FB, lr, lsl #11 + cmp lr, #0x1F + movhs \FB, #(0x1F<<11) + movlo \FB, lr, lsl #11 + // green and r6, \DREG, #(0x3F<<5) @@ -75,7 +102,9 @@ mov lr, \SRC, lsr #(8+2) and lr, lr, #0x3F add r6, lr, r6, lsr #(5+8) - orr \FB, \FB, r6, lsl #5 + cmp r6, #0x3F + orrhs \FB, \FB, #(0x3F<<5) + orrlo \FB, \FB, r6, lsl #5 // blue and lr, \DREG, #0x1F @@ -83,7 +112,9 @@ mov r6, \SRC, lsr #(8+8+3) and r6, r6, #0x1F add lr, r6, lr, lsr #8 - orr \FB, \FB, lr + cmp lr, #0x1F + orrhs \FB, \FB, #0x1F + orrlo \FB, \FB, lr .endif @@ -128,7 +159,7 @@ aligned: subs r2, r2, #2 blo 9f - // The main loop is unrolled twice and process 4 pixels + // The main loop is unrolled twice and processes 4 pixels 8: ldmia r1!, {r4, r5} // stream the source pld [r1, #32] @@ -142,7 +173,7 @@ aligned: // stream the destination pld [r0, #32] pixel r3, r4, r12, 0 - pixel r3, r5, r12, 16 + pixel r3, r5, r12, 1 // effectively, we're getting write-combining by virtue of the // cpu's write-back cache. str r12, [r0, #-4] diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp index e9ca8977f85..4c747650100 100644 --- a/libsysutils/src/FrameworkListener.cpp +++ b/libsysutils/src/FrameworkListener.cpp @@ -56,24 +56,73 @@ void FrameworkListener::registerCmd(FrameworkCommand *cmd) { } void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { - int argc; + FrameworkCommandCollection::iterator i; + int argc = 0; char *argv[FrameworkListener::CMD_ARGS_MAX]; + char tmp[255]; + char *p = data; + char *q = tmp; + bool esc = false; + bool quote = false; + int k; + + memset(argv, 0, sizeof(argv)); + memset(tmp, 0, sizeof(tmp)); + while(*p) { + if (*p == '\\') { + if (esc) { + *q++ = '\\'; + esc = false; + } else + esc = true; + p++; + continue; + } else if (esc) { + if (*p == '"') + *q++ = '"'; + else if (*p == '\\') + *q++ = '\\'; + else { + cli->sendMsg(500, "Unsupported escape sequence", false); + goto out; + } + p++; + esc = false; + continue; + } + + if (*p == '"') { + if (quote) + quote = false; + else + quote = true; + p++; + continue; + } - if (!index(data, '"')) { - char *next = data; - char *field; - int i; - - for (i = 0; (i < FrameworkListener::CMD_ARGS_MAX) && - (argv[i] = strsep(&next, " ")); i++); - argc = i+1; - } else { - LOGD("blehhh not supported"); - return; + *q = *p++; + if (!quote && *q == ' ') { + *q = '\0'; + argv[argc++] = strdup(tmp); + memset(tmp, 0, sizeof(tmp)); + q = tmp; + continue; + } + q++; } - FrameworkCommandCollection::iterator i; + argv[argc++] = strdup(tmp); +#if 0 + for (k = 0; k < argc; k++) { + LOGD("arg[%d] = '%s'", k, argv[k]); + } +#endif + if (quote) { + cli->sendMsg(500, "Unclosed quotes error", false); + goto out; + } + for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i; @@ -81,10 +130,14 @@ void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { if (c->runCommand(cli, argc, argv)) { LOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } - return; + goto out; } } cli->sendMsg(500, "Command not recognized", false); +out: + int j; + for (j = 0; j < argc; j++) + free(argv[j]); return; } diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp index 1a937c296b3..72e128dbb00 100644 --- a/libsysutils/src/SocketListener.cpp +++ b/libsysutils/src/SocketListener.cpp @@ -45,9 +45,26 @@ SocketListener::SocketListener(int socketFd, bool listen) { mClients = new SocketClientCollection(); } +SocketListener::~SocketListener() { + if (mSocketName && mSock > -1) + close(mSock); + + if (mCtrlPipe[0] != -1) { + close(mCtrlPipe[0]); + close(mCtrlPipe[1]); + } + SocketClientCollection::iterator it; + for (it = mClients->begin(); it != mClients->end(); ++it) { + delete (*it); + it = mClients->erase(it); + } + delete mClients; +} + int SocketListener::startListener() { if (!mSocketName && mSock == -1) { + LOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { @@ -64,11 +81,15 @@ int SocketListener::startListener() { } else if (!mListen) mClients->push_back(new SocketClient(mSock)); - if (pipe(mCtrlPipe)) + if (pipe(mCtrlPipe)) { + LOGE("pipe failed (%s)", strerror(errno)); return -1; + } - if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) + if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { + LOGE("pthread_create (%s)", strerror(errno)); return -1; + } return 0; } @@ -88,6 +109,19 @@ int SocketListener::stopListener() { } close(mCtrlPipe[0]); close(mCtrlPipe[1]); + mCtrlPipe[0] = -1; + mCtrlPipe[1] = -1; + + if (mSocketName && mSock > -1) { + close(mSock); + mSock = -1; + } + + SocketClientCollection::iterator it; + for (it = mClients->begin(); it != mClients->end(); ++it) { + delete (*it); + it = mClients->erase(it); + } return 0; } diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c index 4387cebaa0e..0e264a34370 100644 --- a/libzipfile/centraldir.c +++ b/libzipfile/centraldir.c @@ -13,7 +13,7 @@ enum { // central directory entries ENTRY_SIGNATURE = 0x02014b50, ENTRY_LEN = 46, // CentralDirEnt len, excl. var fields - + // local file header LFH_SIZE = 30, }; @@ -73,8 +73,6 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry, unsigned short lastModFileTime; unsigned short lastModFileDate; unsigned long crc32; - unsigned long compressedSize; - unsigned long uncompressedSize; unsigned short extraFieldLength; unsigned short fileCommentLength; unsigned short diskNumberStart; @@ -85,7 +83,7 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry, const unsigned char* fileComment; unsigned int dataOffset; unsigned short lfhExtraFieldSize; - + p = *buf; @@ -106,7 +104,7 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry, lastModFileTime = read_le_short(&p[0x0c]); lastModFileDate = read_le_short(&p[0x0e]); crc32 = read_le_int(&p[0x10]); - compressedSize = read_le_int(&p[0x14]); + entry->compressedSize = read_le_int(&p[0x14]); entry->uncompressedSize = read_le_int(&p[0x18]); entry->fileNameLength = read_le_short(&p[0x1c]); extraFieldLength = read_le_short(&p[0x1e]); @@ -141,14 +139,14 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry, fileComment = NULL; } p += fileCommentLength; - + *buf = p; // the size of the extraField in the central dir is how much data there is, // but the one in the local file header also contains some padding. p = file->buf + localHeaderRelOffset; extraFieldLength = read_le_short(&p[0x1c]); - + dataOffset = localHeaderRelOffset + LFH_SIZE + entry->fileNameLength + extraFieldLength; entry->data = file->buf + dataOffset; @@ -235,7 +233,7 @@ read_central_dir(Zipfile *file) len = (buf+bufsize)-p; for (i=0; i < file->totalEntryCount; i++) { Zipentry* entry = malloc(sizeof(Zipentry)); - memset(entry, sizeof(Zipentry), 0); + memset(entry, 0, sizeof(Zipentry)); err = read_central_directory_entry(file, entry, &p, &len); if (err != 0) { @@ -243,7 +241,7 @@ read_central_dir(Zipfile *file) free(entry); goto bail; } - + // add it to our list entry->next = file->entries; file->entries = entry; @@ -253,4 +251,3 @@ read_central_dir(Zipfile *file) bail: return -1; } - diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c index b52d02df758..a401a9b1685 100644 --- a/libzipfile/zipfile.c +++ b/libzipfile/zipfile.c @@ -82,13 +82,13 @@ uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen) unsigned long crc; int err = 0; int zerr; - + memset(&zstream, 0, sizeof(zstream)); zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; zstream.next_in = (void*)in; - zstream.avail_in = unlen; + zstream.avail_in = clen; zstream.next_out = (Bytef*) out; zstream.avail_out = unlen; zstream.data_type = Z_UNKNOWN; @@ -99,7 +99,7 @@ uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen) if (zerr != Z_OK) { return -1; } - + // uncompress the data zerr = inflate(&zstream, Z_FINISH); if (zerr != Z_STREAM_END) { @@ -107,7 +107,7 @@ uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen) zstream.total_out); err = -1; } - + inflateEnd(&zstream); return err; } diff --git a/logcat/event-log-tags b/logcat/event-log-tags index 6df3792309b..2140b374fc6 100644 --- a/logcat/event-log-tags +++ b/logcat/event-log-tags @@ -21,7 +21,7 @@ # 2: long # 3: string # 4: list -# +# # The data unit is a number taken from the following list: # 1: Number of objects # 2: Number of bytes @@ -40,7 +40,8 @@ 2718 e 2719 configuration_changed (config mask|1|5) -2720 sync (id|3),(event|1|5),(source|1|5) +# "account" is the java hash of the account name +2720 sync (id|3),(event|1|5),(source|1|5),(account|1|5) 2721 cpu (total|1|6),(user|1|6),(system|1|6),(iowait|1|6),(irq|1|6),(softirq|1|6) 2722 battery_level (level|1|6),(voltage|1|1),(temperature|1|1) 2723 battery_status (status|1|5),(health|1|5),(present|1|5),(plugged|1|5),(technology|3) @@ -58,11 +59,11 @@ # This is logged when the partial wake lock (keeping the device awake # regardless of whether the screen is off) is acquired or released. 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3) -# This is logged when battery goes from discharging to charging. +# This is logged when battery goes from discharging to charging. # It lets us count the total amount of time between charges and the discharge level 2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6) # -# Leave IDs through 2739 for more power logs +# Leave IDs through 2739 for more power logs # # This event is logged when the location service uploads location data. @@ -79,8 +80,12 @@ 2744 free_storage_changed (data|2|2) # Device low memory notification and disk space free on the /data partition, in bytes at that time 2745 low_storage (data|2|2) -# disk space free on the /data partition in bytes -2746 free_storage_left (data|2|2) +# disk space free on the /data, /system, and /cache partitions in bytes +2746 free_storage_left (data|2|2),(system|2|2),(cache|2|2) + +# contacts aggregation: time and number of contacts. +# count is negative for query phase, positive for merge phase +2747 contacts_aggregation (aggregation time|2|3), (count|1|1) # when a NotificationManager.notify is called 2750 notification_enqueue (pkg|3),(id|1|5),(notification|3) @@ -94,7 +99,7 @@ 2800 gtalkservice (eventType|1) # This event is logged for GTalk connection state changes. The status field is an int, but # it really contains 4 separate values, each taking up a byte -# (eventType, connection state, connection error, network state) +# (eventType << 24) + (connection state << 16) + (connection error << 8) + network state 2801 gtalk_connection (status|1) 2802 watchdog (Service|3) @@ -108,6 +113,21 @@ 2810 watchdog_vmstat (runtime|2|3),(pgfree|1|1),(pgactivate|1|1),(pgdeactivate|1|1),(pgfault|1|1),(pgmajfault|1|1) 2811 watchdog_requested_reboot (NoWait|1|1),(ScheduleInterval|1|3),(RecheckInterval|1|3),(StartTime|1|3),(Window|1|3),(MinScreenOff|1|3),(MinNextAlarm|1|3) +2820 backup_data_changed (Package|3) +2821 backup_start (Transport|3) +2822 backup_transport_failure (Package|3) +2823 backup_agent_failure (Package|3),(Message|3) +2824 backup_package (Package|3),(Size|1|2) +2825 backup_success (Packages|1|1),(Time|1|3) +2826 backup_reset (Transport|3) +2827 backup_initialize + +2830 restore_start (Transport|3),(Source|2|5) +2831 restore_transport_failure +2832 restore_agent_failure (Package|3),(Message|3) +2833 restore_package (Package|3),(Size|1|2) +2834 restore_success (Packages|1|1),(Time|1|3) + # Device boot timings. We include monotonic clock values because the # intrinsic event log times are wall-clock. # @@ -135,6 +155,67 @@ 3100 boot_progress_pms_ready (time|2|3) # + check activity_launch_time for Home app +# This event is logged when GTalk connection is closed. +# The status field is an int, but contains 2 different values, it's represented as +# +# (networkType << 8) + connection error +# +# the possible error values are +# +# no_error=0, no_network=1, connection_failed=2, unknown_host=3, auth_failed=4, +# auth_expired=5, heart_beat_timeout=6, server_error=7, server_reject_rate_limiting=8, unknown=10 +# +# duration is the connection duration. +4000 gtalk_conn_close (status|1),(duration|1) + +# This event is logged for GTalk heartbeat resets +# interval_and_nt contains both the heartbeat interval and the network type, It's represented as +# (networkType << 16) + interval +# interval is in seconds; network type can be 0 (mobile) or 1 (wifi); ip is the host ip addr. +4001 gtalk_heartbeat_reset (interval_and_nt|1),(ip|3) + +# dvm_gc_info: LIST (LONG, LONG, LONG) +# +# First LONG: +# +# [63] 1 +# [62-24] ASCII process identifier +# [23-12] GC time in ms +# [11- 0] Bytes freed +# +# Second LONG (aggregated heap info): +# +# [63-62] 10 +# [61-60] Reserved; must be zero +# [59-48] Objects freed +# [47-36] Actual size (current footprint) +# [35-24] Allowed size (current hard max) +# [23-12] Objects allocated +# [11- 0] Bytes allocated +# +# Third LONG (zygote heap info): +# +# [63-62] 11 +# [61-60] Reserved; must be zero +# [59-48] Soft limit +# [47-36] Actual size (current footprint) +# [35-24] Allowed size (current hard max) +# [23-12] Objects allocated +# [11- 0] Bytes allocated +# +# Fourth LONG: +# +# [63-48] Reserved; must be zero +# [47-36] dlmallocFootprint +# [35-24] mallinfo: total allocated space +# [23-12] External byte limit +# [11- 0] External bytes allocated +# +# See HeapDebug.c +# +20001 dvm_gc_info (custom|2),(custom|2),(custom|2),(custom|2) +20002 dvm_gc_madvise_info (total|1|2),(zygote|1|2) + # Do not change these names without updating the checkin_events setting in # google3/googledata/wireless/android/provisioning/gservices.config !! # @@ -160,9 +241,9 @@ 30010 am_proc_bound (PID|1|5),(Process Name|3) # Application process died 30011 am_proc_died (PID|1|5),(Process Name|3) -# The Activity Manager failed to pause the given activity. +# The Activity Manager failed to pause the given activity. 30012 am_failed_to_pause (Token|1|5),(Wanting to pause|3),(Currently pausing|3) -# Attempting to pause the current activity +# Attempting to pause the current activity 30013 am_pause_activity (Token|1|5),(Component Name|3) # Application process has been started 30014 am_proc_start (PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3) @@ -208,52 +289,11 @@ # Re-connecting to input method service because we haven't received its interface 32000 imf_force_reconnect_ime (IME|4),(Time Since Connect|2|3),(Showing|1|1) -# dvm_gc_info: LIST (LONG, LONG, LONG) -# -# First LONG: -# -# [63] 1 -# [62-24] ASCII process identifier -# [23-12] GC time in ms -# [11- 0] Bytes freed -# -# Second LONG (aggregated heap info): -# -# [63-62] 10 -# [61-60] Reserved; must be zero -# [59-48] Objects freed -# [47-36] Actual size (current footprint) -# [35-24] Allowed size (current hard max) -# [23-12] Objects allocated -# [11- 0] Bytes allocated -# -# Third LONG (zygote heap info): -# -# [63-62] 11 -# [61-60] Reserved; must be zero -# [59-48] Soft limit -# [47-36] Actual size (current footprint) -# [35-24] Allowed size (current hard max) -# [23-12] Objects allocated -# [11- 0] Bytes allocated -# -# Fourth LONG: -# -# [63-48] Reserved; must be zero -# [47-36] dlmallocFootprint -# [35-24] mallinfo: total allocated space -# [23-12] External byte limit -# [11- 0] External bytes allocated -# -# See HeapDebug.c -# -20001 dvm_gc_info (custom|2),(custom|2),(custom|2),(custom|2) -20002 dvm_gc_madvise_info (total|1|2),(zygote|1|2) - 75000 sqlite_mem_alarm_current (current|1|2) 75001 sqlite_mem_alarm_max (max|1|2) 75002 sqlite_mem_alarm_alloc_attempt (attempts|1|4) 75003 sqlite_mem_released (Memory released|1|2) +75004 sqlite_db_corrupt (Database file corrupt|3) 40000 checkin (Check in time|2|3) @@ -262,28 +302,28 @@ # Connectivity state changed: # [31-13] Reserved for future use # [12- 9] Network subtype (for mobile network, as defined by TelephonyManager) -# [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) +# [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) # [ 2- 0] Network type (as defined by ConnectivityManager) 50020 connectivity_state_changed (custom|1|5) # Wi-Fi network state changed: # [31- 6] Reserved for future use -# [ 5- 0] Detailed state ordinal (as defined by NetworkInfo.DetailedState) +# [ 5- 0] Detailed state ordinal (as defined by NetworkInfo.DetailedState) 50021 wifi_network_state_changed (network_state|1|5) # Wi-Fi supplicant state changed: # [31- 6] Reserved for future use -# [ 5- 0] Supplicant state ordinal (as defined by SupplicantState) +# [ 5- 0] Supplicant state ordinal (as defined by SupplicantState) 50022 wifi_supplicant_state_changed (supplicant_state|1|5) # Wi-Fi driver state changed: # [31- 1] Reserved for future use -# [ 0- 0] Driver start (1) or stopped (0) +# [ 0- 0] Driver start (1) or stopped (0) 50023 wifi_driver_state_changed (driver_state|1|5) # Wi-Fi interface configuration state changed: # [31- 1] Reserved for future use -# [ 0- 0] Interface configuration succeeded (1) or failed (0) +# [ 0- 0] Interface configuration succeeded (1) or failed (0) 50024 wifi_interface_configuration_state_changed (IP_configuration|1|5) # Wi-Fi supplicant connection state changed: @@ -333,7 +373,7 @@ #//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c 51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5) -# db stats. 0 is query, 1 is write (may become more fine grained in the +# db stats. 0 is query, 1 is write (may become more fine grained in the # future) 52000 db_operation (name|3),(op_type|1|5),(time|2|3) @@ -351,5 +391,9 @@ 70101 browser_zoom_level_change (start level|1|5),(end level|1|5),(time|2|3) 70102 browser_double_tap_duration (duration|1|3),(time|2|3) +# aggregation service +70200 aggregation (aggregation time|2|3) +70201 aggregation_test (field1|1|2),(field2|1|2),(field3|1|2),(field4|1|2),(field5|1|2) + # NOTE - the range 1000000-2000000 is reserved for partners and others who # want to define their own log tags without conflicting with the core platform. diff --git a/nexus/Android.mk b/nexus/Android.mk index cd477ef4535..f9f7110867c 100644 --- a/nexus/Android.mk +++ b/nexus/Android.mk @@ -7,23 +7,22 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ main.cpp \ - NetworkManager.cpp \ + NexusCommand.cpp \ CommandListener.cpp \ + Property.cpp \ + PropertyManager.cpp \ + InterfaceConfig.cpp \ + NetworkManager.cpp \ Controller.cpp \ WifiController.cpp \ - LoopController.cpp \ - NexusCommand.cpp \ TiwlanWifiController.cpp \ + TiwlanEventListener.cpp \ + WifiNetwork.cpp \ + WifiStatusPoller.cpp \ + ScanResult.cpp \ Supplicant.cpp \ SupplicantEvent.cpp \ SupplicantListener.cpp \ - VpnController.cpp \ - ScanResult.cpp \ - WifiScanner.cpp \ - WifiNetwork.cpp \ - OpenVpnController.cpp \ - InterfaceConfig.cpp \ - PropertyManager.cpp \ SupplicantState.cpp \ SupplicantEventFactory.cpp \ SupplicantConnectedEvent.cpp \ @@ -34,8 +33,11 @@ LOCAL_SRC_FILES:= \ SupplicantConnectionTimeoutEvent.cpp \ SupplicantDisconnectedEvent.cpp \ SupplicantStatus.cpp \ - TiwlanEventListener.cpp \ + OpenVpnController.cpp \ + VpnController.cpp \ + LoopController.cpp \ DhcpClient.cpp DhcpListener.cpp \ + DhcpState.cpp DhcpEvent.cpp \ LOCAL_MODULE:= nexus diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp index 8eb378bcd02..5973ff51064 100644 --- a/nexus/CommandListener.cpp +++ b/nexus/CommandListener.cpp @@ -31,7 +31,7 @@ #include "NetworkManager.h" #include "WifiController.h" #include "VpnController.h" -#include "ErrorCode.h" +#include "ResponseCode.h" CommandListener::CommandListener() : FrameworkListener("nexus") { @@ -60,11 +60,11 @@ int CommandListener::WifiCreateNetworkCmd::runCommand(SocketClient *cli, WifiNetwork *wn; if (!(wn = wc->createNetwork())) - cli->sendMsg(ErrorCode::OperationFailed, "Failed to create network", true); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to create network", true); else { char tmp[128]; sprintf(tmp, "Created network id %d.", wn->getNetworkId()); - cli->sendMsg(ErrorCode::CommandOkay, tmp, false); + cli->sendMsg(ResponseCode::CommandOkay, tmp, false); } return 0; } @@ -79,9 +79,9 @@ int CommandListener::WifiRemoveNetworkCmd::runCommand(SocketClient *cli, WifiController *wc = (WifiController *) nm->findController("WIFI"); if (wc->removeNetwork(atoi(argv[1]))) - cli->sendMsg(ErrorCode::OperationFailed, "Failed to remove network", true); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove network", true); else { - cli->sendMsg(ErrorCode::CommandOkay, "Network removed.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Network removed.", false); } return 0; } @@ -100,16 +100,16 @@ int CommandListener::WifiScanResultsCmd::runCommand(SocketClient *cli, char buffer[256]; for(it = src->begin(); it != src->end(); ++it) { - sprintf(buffer, "%s:%u:%d:%s:%s", + sprintf(buffer, "%s %u %d %s %s", (*it)->getBssid(), (*it)->getFreq(), (*it)->getLevel(), (*it)->getFlags(), (*it)->getSsid()); - cli->sendMsg(ErrorCode::WifiScanResult, buffer, false); + cli->sendMsg(ResponseCode::WifiScanResult, buffer, false); delete (*it); it = src->erase(it); } delete src; - cli->sendMsg(ErrorCode::CommandOkay, "Scan results complete.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Scan results complete.", false); return 0; } @@ -128,12 +128,12 @@ int CommandListener::WifiListNetworksCmd::runCommand(SocketClient *cli, for(it = src->begin(); it != src->end(); ++it) { sprintf(buffer, "%d:%s", (*it)->getNetworkId(), (*it)->getSsid()); - cli->sendMsg(ErrorCode::WifiNetworkList, buffer, false); + cli->sendMsg(ResponseCode::WifiNetworkList, buffer, false); delete (*it); } delete src; - cli->sendMsg(ErrorCode::CommandOkay, "Network listing complete.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Network listing complete.", false); return 0; } @@ -159,14 +159,14 @@ int CommandListener::GetCmd::runCommand(SocketClient *cli, int argc, char **argv char *tmp; asprintf(&tmp, "%s %s", argv[1], val); - cli->sendMsg(ErrorCode::PropertyRead, tmp, false); + cli->sendMsg(ResponseCode::PropertyRead, tmp, false); free(tmp); - cli->sendMsg(ErrorCode::CommandOkay, "Property read.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Property read.", false); return 0; out_inval: errno = EINVAL; - cli->sendMsg(ErrorCode::CommandParameterError, "Failed to read property.", true); + cli->sendMsg(ResponseCode::CommandParameterError, "Failed to read property.", true); return 0; } @@ -179,12 +179,12 @@ int CommandListener::SetCmd::runCommand(SocketClient *cli, int argc, if (NetworkManager::Instance()->getPropMngr()->set(argv[1], argv[2])) goto out_inval; - cli->sendMsg(ErrorCode::CommandOkay, "Property set.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Property set.", false); return 0; out_inval: errno = EINVAL; - cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set property.", true); + cli->sendMsg(ResponseCode::CommandParameterError, "Failed to set property.", true); return 0; } @@ -194,10 +194,14 @@ CommandListener::ListCmd::ListCmd() : int CommandListener::ListCmd::runCommand(SocketClient *cli, int argc, char **argv) { android::List *pc; + char *prefix = NULL; - if (!(pc = NetworkManager::Instance()->getPropMngr()->createPropertyList())) { + if (argc > 1) + prefix = argv[1]; + + if (!(pc = NetworkManager::Instance()->getPropMngr()->createPropertyList(prefix))) { errno = ENODATA; - cli->sendMsg(ErrorCode::CommandParameterError, "Failed to list properties.", true); + cli->sendMsg(ResponseCode::CommandParameterError, "Failed to list properties.", true); return 0; } @@ -218,7 +222,7 @@ int CommandListener::ListCmd::runCommand(SocketClient *cli, int argc, char **arg free((*it)); continue; } - cli->sendMsg(ErrorCode::PropertyList, buf, false); + cli->sendMsg(ResponseCode::PropertyList, buf, false); free(buf); free((*it)); @@ -226,6 +230,6 @@ int CommandListener::ListCmd::runCommand(SocketClient *cli, int argc, char **arg delete pc; - cli->sendMsg(ErrorCode::CommandOkay, "Properties list complete.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Properties list complete.", false); return 0; } diff --git a/nexus/Controller.cpp b/nexus/Controller.cpp index 17fb5193988..f6a24361cf0 100644 --- a/nexus/Controller.cpp +++ b/nexus/Controller.cpp @@ -30,6 +30,7 @@ #include #include "Controller.h" +#include "InterfaceConfig.h" extern "C" int init_module(void *, unsigned int, const char *); extern "C" int delete_module(const char *, unsigned int); @@ -57,16 +58,6 @@ int Controller::stop() { return 0; } -int Controller::set(const char *name, const char *value) { - errno = ENOENT; - return -1; -} - -const char *Controller::get(const char *name, char *buffer, size_t maxsize) { - errno = ENOENT; - return NULL; -} - int Controller::loadKernelModule(char *modpath, const char *args) { void *module; unsigned int size; @@ -164,13 +155,11 @@ void *Controller::loadFile(char *filename, unsigned int *_size) int Controller::bindInterface(const char *ifname) { mBoundInterface = strdup(ifname); - LOGD("Controller %s bound to %s", mName, ifname); return 0; } int Controller::unbindInterface(const char *ifname) { free(mBoundInterface); mBoundInterface = NULL; - LOGD("Controller %s unbound from %s", mName, ifname); return 0; } diff --git a/nexus/Controller.h b/nexus/Controller.h index af03d2e59df..e7e17c51f6c 100644 --- a/nexus/Controller.h +++ b/nexus/Controller.h @@ -26,9 +26,8 @@ class PropertyManager; class IControllerHandler; #include "PropertyManager.h" -#include "IPropertyProvider.h" -class Controller : public IPropertyProvider { +class Controller { /* * Name of this controller - WIFI/VPN/USBNET/BTNET/BTDUN/LOOP/etc */ @@ -54,11 +53,7 @@ class Controller : public IPropertyProvider { const char *getName() { return mName; } const char *getBoundInterface() { return mBoundInterface; } - - /* IPropertyProvider methods */ - virtual int set(const char *name, const char *value); - virtual const char *get(const char *name, char *buffer, size_t maxsize); - + protected: int loadKernelModule(char *modpath, const char *args); bool isKernelModuleLoaded(const char *modtag); diff --git a/nexus/DhcpClient.cpp b/nexus/DhcpClient.cpp index 2bd9c68f15d..a5654d28d58 100644 --- a/nexus/DhcpClient.cpp +++ b/nexus/DhcpClient.cpp @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #define LOG_TAG "DhcpClient" #include @@ -29,6 +31,7 @@ #include "DhcpState.h" #include "DhcpListener.h" #include "IDhcpEventHandlers.h" +#include "Controller.h" extern "C" { int ifc_disable(const char *ifname); @@ -54,9 +57,13 @@ char *dhcp_get_errmsg(); } DhcpClient::DhcpClient(IDhcpEventHandlers *handlers) : - mState(DhcpState::STOPPED), mHandlers(handlers) { + mState(DhcpState::INIT), mHandlers(handlers) { mServiceManager = new ServiceManager(); mListener = NULL; + mListenerSocket = NULL; + mController = NULL; + mDoArpProbe = false; + pthread_mutex_init(&mLock, NULL); } DhcpClient::~DhcpClient() { @@ -65,41 +72,89 @@ DhcpClient::~DhcpClient() { delete mListener; } -int DhcpClient::start(const char *interface) { - +int DhcpClient::start(Controller *c) { + LOGD("Starting DHCP service (arp probe = %d)", mDoArpProbe); char svc[PROPERTY_VALUE_MAX]; - snprintf(svc, sizeof(svc), "dhcpcd_ng:%s", interface); + snprintf(svc, + sizeof(svc), + "dhcpcd:%s%s", + (!mDoArpProbe ? "-A " : ""), + c->getBoundInterface()); + + pthread_mutex_lock(&mLock); + + if (mController) { + pthread_mutex_unlock(&mLock); + errno = EBUSY; + return -1; + } + mController = c; + + sockaddr_in addr; + if ((mListenerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + LOGE("Failed to create DHCP listener socket"); + pthread_mutex_unlock(&mLock); + return -1; + } + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = htons(DhcpClient::STATUS_MONITOR_PORT); + + if (bind(mListenerSocket, (struct sockaddr *) &addr, sizeof(addr))) { + LOGE("Failed to bind DHCP listener socket"); + close(mListenerSocket); + mListenerSocket = -1; + pthread_mutex_unlock(&mLock); + return -1; + } if (mServiceManager->start(svc)) { LOGE("Failed to start dhcp service"); + pthread_mutex_unlock(&mLock); return -1; } - mListener = new DhcpListener(mHandlers); + mListener = new DhcpListener(mController, mListenerSocket, mHandlers); if (mListener->startListener()) { LOGE("Failed to start listener"); #if 0 - mServiceManager->stop("dhcpcd_ng"); + mServiceManager->stop("dhcpcd"); return -1; #endif delete mListener; mListener = NULL; + pthread_mutex_unlock(&mLock); } - mState = DhcpState::STARTED; - + pthread_mutex_unlock(&mLock); return 0; } int DhcpClient::stop() { + pthread_mutex_lock(&mLock); + if (!mController) { + pthread_mutex_unlock(&mLock); + return 0; + } + if (mListener) { mListener->stopListener(); delete mListener; mListener = NULL; } + close(mListenerSocket); - if (mServiceManager->stop("dhcpcd_ng")) + if (mServiceManager->stop("dhcpcd")) { LOGW("Failed to stop DHCP service (%s)", strerror(errno)); - mState = DhcpState::STOPPED; + // XXX: Kill it the hard way.. but its gotta go! + } + + mController = NULL; + pthread_mutex_unlock(&mLock); return 0; } + +void DhcpClient::setDoArpProbe(bool probe) { + mDoArpProbe = probe; +} diff --git a/nexus/DhcpClient.h b/nexus/DhcpClient.h index e0a2784b528..42bfda07342 100644 --- a/nexus/DhcpClient.h +++ b/nexus/DhcpClient.h @@ -18,23 +18,36 @@ #ifndef _DhcpClient_H #define _DhcpClient_H +#include + class IDhcpEventHandlers; class ServiceManager; class DhcpListener; +class Controller; class DhcpClient { +public: + static const int STATUS_MONITOR_PORT = 6666; + +private: int mState; IDhcpEventHandlers *mHandlers; ServiceManager *mServiceManager; DhcpListener *mListener; + int mListenerSocket; + pthread_mutex_t mLock; + Controller *mController; + bool mDoArpProbe; public: DhcpClient(IDhcpEventHandlers *handlers); virtual ~DhcpClient(); int getState() { return mState; } + bool getDoArpProbe() { return mDoArpProbe; } + void setDoArpProbe(bool probe); - int start(const char *interface); + int start(Controller *c); int stop(); }; diff --git a/nexus/DhcpEvent.cpp b/nexus/DhcpEvent.cpp new file mode 100644 index 00000000000..58893f4094c --- /dev/null +++ b/nexus/DhcpEvent.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "DhcpEvent" +#include + +#include "DhcpEvent.h" + +char *DhcpEvent::toString(int val, char *buffer, int max) { + if (val == DhcpEvent::UNKNOWN) + strncpy(buffer, "UNKNOWN", max); + else if (val == DhcpEvent::STOP) + strncpy(buffer, "STOP", max); + else if (val == DhcpEvent::RENEW) + strncpy(buffer, "RENEW", max); + else if (val == DhcpEvent::RELEASE) + strncpy(buffer, "RELEASE", max); + else if (val == DhcpEvent::TIMEOUT) + strncpy(buffer, "TIMEOUT", max); + else + strncpy(buffer, "(internal error)", max); + + return buffer; +} + +int DhcpEvent::parseString(const char *buffer) { + if (!strcasecmp(buffer, "UNKNOWN")) + return DhcpEvent::UNKNOWN; + else if (!strcasecmp(buffer, "STOP")) + return DhcpEvent::STOP; + else if (!strcasecmp(buffer, "RENEW")) + return DhcpEvent::RENEW; + else if (!strcasecmp(buffer, "RELEASE")) + return DhcpEvent::RELEASE; + else if (!strcasecmp(buffer, "TIMEOUT")) + return DhcpEvent::TIMEOUT; + else { + LOGW("Bad event '%s'", buffer); + return -1; + } +} diff --git a/nexus/IPropertyProvider.h b/nexus/DhcpEvent.h similarity index 63% rename from nexus/IPropertyProvider.h rename to nexus/DhcpEvent.h index 17ad5f8ceb7..f77834dc396 100644 --- a/nexus/IPropertyProvider.h +++ b/nexus/DhcpEvent.h @@ -14,20 +14,20 @@ * limitations under the License. */ -#ifndef _IPROPERTY_PROVIDER_H -#define _IPROPERTY_PROVIDER_H +#ifndef _DHCP_EVENT_H +#define _DHCP_EVENT_H -#include -#include +class DhcpEvent { +public: + static const int UNKNOWN = 0; + static const int STOP = 1; + static const int RENEW = 2; + static const int RELEASE = 3; + static const int TIMEOUT = 4; -#include + static char *toString(int val, char *buffer, int max); -class IPropertyProvider { -public: - virtual int set(const char *name, const char *value) = 0; - virtual const char *get(const char *name, char *buffer, size_t max) = 0; + static int parseString(const char *buffer); }; -typedef android::List IPropertyProviderCollection; - #endif diff --git a/nexus/DhcpListener.cpp b/nexus/DhcpListener.cpp index 2d07ee85dbd..afa68ebdb17 100644 --- a/nexus/DhcpListener.cpp +++ b/nexus/DhcpListener.cpp @@ -14,21 +14,95 @@ * limitations under the License. */ +#include +#include +#include +#include + #define LOG_TAG "DhcpListener" #include #include #include "IDhcpEventHandlers.h" +#include "DhcpState.h" +#include "DhcpEvent.h" +#include "Controller.h" -DhcpListener::DhcpListener(IDhcpEventHandlers *handlers) : - SocketListener("dhcp_ng", false) { +DhcpListener::DhcpListener(Controller *c, int socket, IDhcpEventHandlers *handlers) : + SocketListener(socket, false) { mHandlers = handlers; + mController = c; } DhcpListener::~DhcpListener() { } bool DhcpListener::onDataAvailable(SocketClient *cli) { - LOGD("onDataAvailable()"); + char buffer[255]; + int rc; + + if ((rc = read(cli->getSocket(), buffer, sizeof(buffer))) < 0) { + LOGW("Error reading dhcp status msg (%s)", strerror(errno)); + return true; + } + + if (!strncmp(buffer, "STATE:", 6)) { + char *next = buffer; + char *tmp; + int i; + + for (i = 0; i < 2; i++) { + if (!(tmp = strsep(&next, ":"))) { + LOGW("Error parsing state '%s'", buffer); + return true; + } + } + + int st = DhcpState::parseString(tmp); + mHandlers->onDhcpStateChanged(mController, st); + } else if (!strncmp(buffer, "ADDRINFO:", 9)) { + char *next = buffer + 9; + struct in_addr ipaddr, netmask, gateway, broadcast, dns1, dns2; + + if (!inet_aton(strsep(&next, ":"), &ipaddr)) { + LOGW("Malformatted IP specified"); + } + if (!inet_aton(strsep(&next, ":"), &netmask)) { + LOGW("Malformatted netmask specified"); + } + if (!inet_aton(strsep(&next, ":"), &broadcast)) { + LOGW("Malformatted broadcast specified"); + } + if (!inet_aton(strsep(&next, ":"), &gateway)) { + LOGW("Malformatted gateway specified"); + } + if (!inet_aton(strsep(&next, ":"), &dns1)) { + LOGW("Malformatted dns1 specified"); + } + if (!inet_aton(strsep(&next, ":"), &dns2)) { + LOGW("Malformatted dns2 specified"); + } + mHandlers->onDhcpLeaseUpdated(mController, &ipaddr, &netmask, + &broadcast, &gateway, &dns1, &dns2); + + } else if (!strncmp(buffer, "EVENT:", 6)) { + char *next = buffer; + char *tmp; + int i; + + for (i = 0; i < 2; i++) { + if (!(tmp = strsep(&next, ":"))) { + LOGW("Error parsing event '%s'", buffer); + return true; + } + } + + int ev = DhcpEvent::parseString(tmp); + mHandlers->onDhcpEvent(mController, ev); + + } else { + LOGW("Unknown DHCP monitor msg '%s'", buffer); + } + return true; } diff --git a/nexus/DhcpListener.h b/nexus/DhcpListener.h index bfc5a3771a2..ca6fe378867 100644 --- a/nexus/DhcpListener.h +++ b/nexus/DhcpListener.h @@ -20,13 +20,15 @@ #include class IDhcpEventHandlers; +class Controller; class DhcpListener : public SocketListener { IDhcpEventHandlers *mHandlers; + Controller *mController; public: - DhcpListener(IDhcpEventHandlers *handlers); + DhcpListener(Controller *c, int socket, IDhcpEventHandlers *handlers); virtual ~DhcpListener(); private: diff --git a/nexus/DhcpState.cpp b/nexus/DhcpState.cpp new file mode 100644 index 00000000000..c9d5135812d --- /dev/null +++ b/nexus/DhcpState.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "DhcpState" +#include + +#include "DhcpState.h" + +char *DhcpState::toString(int val, char *buffer, int max) { + if (val == DhcpState::INIT) + strncpy(buffer, "INIT", max); + else if (val == DhcpState::DISCOVERING) + strncpy(buffer, "DISCOVERING", max); + else if (val == DhcpState::REQUESTING) + strncpy(buffer, "REQUESTING", max); + else if (val == DhcpState::BOUND) + strncpy(buffer, "BOUND", max); + else if (val == DhcpState::RENEWING) + strncpy(buffer, "RENEWING", max); + else if (val == DhcpState::REBINDING) + strncpy(buffer, "REBINDING", max); + else if (val == DhcpState::REBOOT) + strncpy(buffer, "REBOOT", max); + else if (val == DhcpState::RENEW_REQUESTED) + strncpy(buffer, "RENEW_REQUESTED", max); + else if (val == DhcpState::INIT_IPV4LL) + strncpy(buffer, "INIT_IPV4LL", max); + else if (val == DhcpState::PROBING) + strncpy(buffer, "PROBING", max); + else if (val == DhcpState::ANNOUNCING) + strncpy(buffer, "ANNOUNCING", max); + else + strncpy(buffer, "(internal error)", max); + + return buffer; +} + +int DhcpState::parseString(const char *buffer) { + if (!strcasecmp(buffer, "INIT")) + return DhcpState::INIT; + else if (!strcasecmp(buffer, "DISCOVERING")) + return DhcpState::DISCOVERING; + else if (!strcasecmp(buffer, "REQUESTING")) + return DhcpState::REQUESTING; + else if (!strcasecmp(buffer, "BOUND")) + return DhcpState::BOUND; + else if (!strcasecmp(buffer, "RENEWING")) + return DhcpState::RENEWING; + else if (!strcasecmp(buffer, "REBINDING")) + return DhcpState::REBINDING; + else if (!strcasecmp(buffer, "REBOOT")) + return DhcpState::REBOOT; + else if (!strcasecmp(buffer, "RENEW_REQUESTED")) + return DhcpState::INIT_IPV4LL; + else if (!strcasecmp(buffer, "INIT_IPV4LL")) + return DhcpState::INIT_IPV4LL; + else if (!strcasecmp(buffer, "PROBING")) + return DhcpState::PROBING; + else if (!strcasecmp(buffer, "ANNOUNCING")) + return DhcpState::ANNOUNCING; + else { + LOGW("Bad state '%s'", buffer); + return -1; + } +} diff --git a/nexus/DhcpState.h b/nexus/DhcpState.h index 27d7c7e37e9..041c5d24eb4 100644 --- a/nexus/DhcpState.h +++ b/nexus/DhcpState.h @@ -14,14 +14,26 @@ * limitations under the License. */ -#ifndef _DhcpState_H -#define _DhcpState_H +#ifndef _DHCP_STATE_H +#define _DHCP_STATE_H class DhcpState { public: - static const int UNKNOWN = 0; - static const int STOPPED = 1; - static const int STARTED = 2; + static const int INIT = 0; + static const int DISCOVERING = 1; + static const int REQUESTING = 2; + static const int BOUND = 3; + static const int RENEWING = 4; + static const int REBINDING = 5; + static const int REBOOT = 6; + static const int RENEW_REQUESTED = 7; + static const int INIT_IPV4LL = 8; + static const int PROBING = 9; + static const int ANNOUNCING = 10; + + static char *toString(int val, char *buffer, int max); + + static int parseString(const char *buffer); }; #endif diff --git a/nexus/IControllerHandler.h b/nexus/IControllerHandler.h index f7be39cea66..3151587d1e0 100644 --- a/nexus/IControllerHandler.h +++ b/nexus/IControllerHandler.h @@ -22,8 +22,11 @@ class InterfaceConfig; class IControllerHandler { public: - virtual void onInterfaceConnected(Controller *c, const InterfaceConfig *cfg) = 0; - virtual void onInterfaceDisconnected(Controller *c, const char *name) = 0; + virtual ~IControllerHandler() {} + virtual void onInterfaceConnected(Controller *c) = 0; + virtual void onInterfaceDisconnected(Controller *c) = 0; + virtual void onControllerSuspending(Controller *c) = 0; + virtual void onControllerResumed(Controller *c) = 0; }; #endif diff --git a/nexus/IDhcpEventHandlers.h b/nexus/IDhcpEventHandlers.h index 3f51f645dc1..2568f09470d 100644 --- a/nexus/IDhcpEventHandlers.h +++ b/nexus/IDhcpEventHandlers.h @@ -20,6 +20,14 @@ class IDhcpEventHandlers { public: + virtual ~IDhcpEventHandlers() {} + virtual void onDhcpStateChanged(Controller *c, int state) = 0; + virtual void onDhcpEvent(Controller *c, int event) = 0; + virtual void onDhcpLeaseUpdated(Controller *c, + struct in_addr *addr, struct in_addr *net, + struct in_addr *brd, + struct in_addr *gw, struct in_addr *dns1, + struct in_addr *dns2) = 0; }; #endif diff --git a/nexus/ISupplicantEventHandler.h b/nexus/ISupplicantEventHandler.h index b7fd17b56fe..1a3aa07f57f 100644 --- a/nexus/ISupplicantEventHandler.h +++ b/nexus/ISupplicantEventHandler.h @@ -27,6 +27,7 @@ class SupplicantDisconnectedEvent; class ISupplicantEventHandler { public: + virtual ~ISupplicantEventHandler(){} virtual void onAssociatingEvent(SupplicantAssociatingEvent *evt) = 0; virtual void onAssociatedEvent(SupplicantAssociatedEvent *evt) = 0; virtual void onConnectedEvent(SupplicantConnectedEvent *evt) = 0; diff --git a/nexus/IWifiStatusPollerHandler.h b/nexus/IWifiStatusPollerHandler.h new file mode 100644 index 00000000000..9b949459006 --- /dev/null +++ b/nexus/IWifiStatusPollerHandler.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IWIFISTATUSPOLLER_HANDLER_H +#define _IWIFISTATUSPOLLER_HANDLER_H + +class IWifiStatusPollerHandler { +public: + virtual ~IWifiStatusPollerHandler() {} + virtual void onStatusPollInterval() = 0; +}; + +#endif diff --git a/nexus/InterfaceConfig.cpp b/nexus/InterfaceConfig.cpp index 66861d02a0a..832cbcabd3a 100644 --- a/nexus/InterfaceConfig.cpp +++ b/nexus/InterfaceConfig.cpp @@ -23,147 +23,72 @@ #include "InterfaceConfig.h" #include "NetworkManager.h" -const char *InterfaceConfig::PropertyNames[] = { "dhcp", "ip", - "netmask", - "gateway", "dns1", "dns2", - "dns3", '\0' }; - -InterfaceConfig::InterfaceConfig(const char *prop_prefix) { - mPropPrefix = strdup(prop_prefix); - mUseDhcp = true; - registerProperties(); +InterfaceConfig::InterfaceConfig(bool propertiesReadOnly) { + mStaticProperties.propIp = new IPV4AddressPropertyHelper("Addr", propertiesReadOnly, &mIp); + mStaticProperties.propNetmask = new IPV4AddressPropertyHelper("Netmask", propertiesReadOnly, &mNetmask); + mStaticProperties.propGateway = new IPV4AddressPropertyHelper("Gateway", propertiesReadOnly, &mGateway); + mStaticProperties.propBroadcast = new IPV4AddressPropertyHelper("Broadcast", propertiesReadOnly, &mBroadcast); + mStaticProperties.propDns = new InterfaceDnsProperty(this, propertiesReadOnly); } InterfaceConfig::~InterfaceConfig() { - unregisterProperties(); - free(mPropPrefix); + delete mStaticProperties.propIp; + delete mStaticProperties.propNetmask; + delete mStaticProperties.propGateway; + delete mStaticProperties.propBroadcast; + delete mStaticProperties.propDns; } -InterfaceConfig::InterfaceConfig(const char *prop_prefix, - const char *ip, const char *nm, - const char *gw, const char *dns1, const char *dns2, - const char *dns3) { - mPropPrefix = strdup(prop_prefix); - mUseDhcp = false; +void InterfaceConfig::setIp(struct in_addr *addr) { + memcpy(&mIp, addr, sizeof(struct in_addr)); +} - if (!inet_aton(ip, &mIp)) - LOGW("Unable to parse ip (%s)", ip); - if (!inet_aton(nm, &mNetmask)) - LOGW("Unable to parse netmask (%s)", nm); - if (!inet_aton(gw, &mGateway)) - LOGW("Unable to parse gateway (%s)", gw); - if (!inet_aton(dns1, &mDns1)) - LOGW("Unable to parse dns1 (%s)", dns1); - if (!inet_aton(dns2, &mDns2)) - LOGW("Unable to parse dns2 (%s)", dns2); - if (!inet_aton(dns3, &mDns3)) - LOGW("Unable to parse dns3 (%s)", dns3); - registerProperties(); +void InterfaceConfig::setNetmask(struct in_addr *addr) { + memcpy(&mNetmask, addr, sizeof(struct in_addr)); } -InterfaceConfig::InterfaceConfig(const char *prop_prefix, - const struct in_addr *ip, - const struct in_addr *nm, const struct in_addr *gw, - const struct in_addr *dns1, const struct in_addr *dns2, - const struct in_addr *dns3) { - mPropPrefix = strdup(prop_prefix); - mUseDhcp = false; +void InterfaceConfig::setGateway(struct in_addr *addr) { + memcpy(&mGateway, addr, sizeof(struct in_addr)); +} - memcpy(&mIp, ip, sizeof(struct in_addr)); - memcpy(&mNetmask, nm, sizeof(struct in_addr)); - memcpy(&mGateway, gw, sizeof(struct in_addr)); - memcpy(&mDns1, dns1, sizeof(struct in_addr)); - memcpy(&mDns2, dns2, sizeof(struct in_addr)); - memcpy(&mDns3, dns3, sizeof(struct in_addr)); - registerProperties(); +void InterfaceConfig::setBroadcast(struct in_addr *addr) { + memcpy(&mBroadcast, addr, sizeof(struct in_addr)); } -int InterfaceConfig::registerProperties() { - for (const char **p = InterfaceConfig::PropertyNames; *p != '\0'; p++) { - char *tmp; - asprintf(&tmp, "%s.if.%s", mPropPrefix, *p); +void InterfaceConfig::setDns(int idx, struct in_addr *addr) { + memcpy(&mDns[idx], addr, sizeof(struct in_addr)); +} - if (NetworkManager::Instance()->getPropMngr()->registerProperty(tmp, - this)) { - free(tmp); - return -1; - } - free(tmp); - } +int InterfaceConfig::attachProperties(PropertyManager *pm, const char *nsName) { + pm->attachProperty(nsName, mStaticProperties.propIp); + pm->attachProperty(nsName, mStaticProperties.propNetmask); + pm->attachProperty(nsName, mStaticProperties.propGateway); + pm->attachProperty(nsName, mStaticProperties.propBroadcast); + pm->attachProperty(nsName, mStaticProperties.propDns); return 0; } -int InterfaceConfig::unregisterProperties() { - for (const char **p = InterfaceConfig::PropertyNames; *p != '\0'; p++) { - char *tmp; - asprintf(&tmp, "%s.if.%s", mPropPrefix, *p); - - if (NetworkManager::Instance()->getPropMngr()->unregisterProperty(tmp)) - LOGW("Unable to remove property '%s' (%s)", tmp, strerror(errno)); - free(tmp); - } +int InterfaceConfig::detachProperties(PropertyManager *pm, const char *nsName) { + pm->detachProperty(nsName, mStaticProperties.propIp); + pm->detachProperty(nsName, mStaticProperties.propNetmask); + pm->detachProperty(nsName, mStaticProperties.propGateway); + pm->detachProperty(nsName, mStaticProperties.propBroadcast); + pm->detachProperty(nsName, mStaticProperties.propDns); return 0; } -int InterfaceConfig::set(const char *name, const char *value) { - const char *n; - - for (n = &name[strlen(name)]; *n != '.'; n--); - n++; - - if (!strcasecmp(n, "name")) { - errno = EROFS; - return -1; - } else if (!strcasecmp(n, "ip") && !inet_aton(value, &mIp)) - goto out_inval; - else if (!strcasecmp(n, "dhcp")) - mUseDhcp = (atoi(value) == 0 ? false : true); - else if (!strcasecmp(n, "netmask") && !inet_aton(value, &mNetmask)) - goto out_inval; - else if (!strcasecmp(n, "gateway") && !inet_aton(value, &mGateway)) - goto out_inval; - else if (!strcasecmp(n, "dns1") && !inet_aton(value, &mDns1)) - goto out_inval; - else if (!strcasecmp(n, "dns2") && !inet_aton(value, &mDns2)) - goto out_inval; - else if (!strcasecmp(n, "dns3") && !inet_aton(value, &mDns3)) - goto out_inval; - else { - errno = ENOENT; - return -1; - } +InterfaceConfig::InterfaceDnsProperty::InterfaceDnsProperty(InterfaceConfig *c, + bool ro) : + IPV4AddressProperty("Dns", ro, 2) { + mCfg = c; +} +int InterfaceConfig::InterfaceDnsProperty::set(int idx, struct in_addr *value) { + memcpy(&mCfg->mDns[idx], value, sizeof(struct in_addr)); return 0; - -out_inval: - errno = EINVAL; - return -1; } - -const char *InterfaceConfig::get(const char *name, char *buffer, size_t max) { - const char *n; - - for (n = &name[strlen(name)]; *n != '.'; n--); - n++; - - if (!strcasecmp(n, "ip")) - strncpy(buffer, inet_ntoa(mIp), max); - else if (!strcasecmp(n, "dhcp")) - snprintf(buffer, max, "%d", mUseDhcp); - else if (!strcasecmp(n, "netmask")) - strncpy(buffer, inet_ntoa(mNetmask), max); - else if (!strcasecmp(n, "gateway")) - strncpy(buffer, inet_ntoa(mGateway), max); - else if (!strcasecmp(n, "dns1")) - strncpy(buffer, inet_ntoa(mDns1), max); - else if (!strcasecmp(n, "dns2")) - strncpy(buffer, inet_ntoa(mDns2), max); - else if (!strcasecmp(n, "dns3")) - strncpy(buffer, inet_ntoa(mDns3), max); - else { - strncpy(buffer, "(internal error)", max); - errno = ENOENT; - return NULL; - } - return buffer; +int InterfaceConfig::InterfaceDnsProperty::get(int idx, struct in_addr *buf) { + memcpy(buf, &mCfg->mDns[idx], sizeof(struct in_addr)); + return 0; } + diff --git a/nexus/InterfaceConfig.h b/nexus/InterfaceConfig.h index d97f20b2dce..3fc73909c55 100644 --- a/nexus/InterfaceConfig.h +++ b/nexus/InterfaceConfig.h @@ -22,53 +22,58 @@ #include #include -#include "IPropertyProvider.h" - +#include "Property.h" class PropertyManager; -class InterfaceConfig : public IPropertyProvider { -public: - static const char *PropertyNames[]; +class InterfaceConfig { + class InterfaceDnsProperty; + friend class InterfaceConfig::InterfaceDnsProperty; + + struct { + IPV4AddressPropertyHelper *propIp; + IPV4AddressPropertyHelper *propNetmask; + IPV4AddressPropertyHelper *propGateway; + IPV4AddressPropertyHelper *propBroadcast; + InterfaceDnsProperty *propDns; + } mStaticProperties; -private: - char *mPropPrefix; - bool mUseDhcp; struct in_addr mIp; struct in_addr mNetmask; struct in_addr mGateway; - struct in_addr mDns1; - struct in_addr mDns2; - struct in_addr mDns3; + struct in_addr mBroadcast; + struct in_addr mDns[2]; public: - InterfaceConfig(const char *prop_prefix); - InterfaceConfig(const char *prop_prefix, - const char *ip, const char *nm, - const char *gw, const char *dns1, const char *dns2, - const char *dns3); - - InterfaceConfig(const char *prop_prefix, - const struct in_addr *ip, - const struct in_addr *nm, const struct in_addr *gw, - const struct in_addr *dns1, const struct in_addr *dns2, - const struct in_addr *dns3); - + InterfaceConfig(bool propertiesReadOnly); virtual ~InterfaceConfig(); int set(const char *name, const char *value); const char *get(const char *name, char *buffer, size_t maxsize); - bool getUseDhcp() const { return mUseDhcp; } const struct in_addr &getIp() const { return mIp; } const struct in_addr &getNetmask() const { return mNetmask; } const struct in_addr &getGateway() const { return mGateway; } - const struct in_addr &getDns1() const { return mDns1; } - const struct in_addr &getDns2() const { return mDns2; } - const struct in_addr &getDns3() const { return mDns3; } + const struct in_addr &getBroadcast() const { return mBroadcast; } + const struct in_addr &getDns(int idx) const { return mDns[idx]; } + + void setIp(struct in_addr *addr); + void setNetmask(struct in_addr *addr); + void setGateway(struct in_addr *addr); + void setBroadcast(struct in_addr *addr); + void setDns(int idx, struct in_addr *addr); + + int attachProperties(PropertyManager *pm, const char *nsName); + int detachProperties(PropertyManager *pm, const char *nsName); private: - int registerProperties(); - int unregisterProperties(); + + class InterfaceDnsProperty : public IPV4AddressProperty { + InterfaceConfig *mCfg; + public: + InterfaceDnsProperty(InterfaceConfig *cfg, bool ro); + int set(int idx, struct in_addr *value); + int get(int idx, struct in_addr *buffer); + }; }; diff --git a/nexus/LoopController.cpp b/nexus/LoopController.cpp index 5cfb1fecb2b..f8e01d7c283 100644 --- a/nexus/LoopController.cpp +++ b/nexus/LoopController.cpp @@ -21,14 +21,5 @@ LoopController::LoopController(PropertyManager *propmngr, IControllerHandler *handlers) : - Controller("LOOP", propmngr, handlers) { + Controller("loop", propmngr, handlers) { } - -int LoopController::set(const char *name, const char *value) { - return Controller::set(name, value); -} - -const char *LoopController::get(const char *name, char *buffer, size_t maxsize) { - return Controller::get(name, buffer, maxsize); -} - diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp index 7450b951b6d..e0df4096a1f 100644 --- a/nexus/NetworkManager.cpp +++ b/nexus/NetworkManager.cpp @@ -24,6 +24,9 @@ #include "NetworkManager.h" #include "InterfaceConfig.h" #include "DhcpClient.h" +#include "DhcpState.h" +#include "DhcpEvent.h" +#include "ResponseCode.h" NetworkManager *NetworkManager::sInstance = NULL; @@ -35,8 +38,9 @@ NetworkManager *NetworkManager::Instance() { NetworkManager::NetworkManager(PropertyManager *propMngr) { mBroadcaster = NULL; - mControllers = new ControllerCollection(); + mControllerBindings = new ControllerBindingCollection(); mPropMngr = propMngr; + mLastDhcpState = DhcpState::INIT; mDhcp = new DhcpClient(this); } @@ -51,17 +55,17 @@ int NetworkManager::run() { } int NetworkManager::attachController(Controller *c) { - mControllers->push_back(c); + ControllerBinding *cb = new ControllerBinding(c); + mControllerBindings->push_back(cb); return 0; } int NetworkManager::startControllers() { int rc = 0; - ControllerCollection::iterator i; + ControllerBindingCollection::iterator it; - for (i = mControllers->begin(); i != mControllers->end(); ++i) { - int irc = (*i)->start(); - LOGD("Controller '%s' start rc = %d", (*i)->getName(), irc); + for (it = mControllerBindings->begin(); it != mControllerBindings->end(); ++it) { + int irc = (*it)->getController()->start(); if (irc && !rc) rc = irc; } @@ -70,52 +74,132 @@ int NetworkManager::startControllers() { int NetworkManager::stopControllers() { int rc = 0; - ControllerCollection::iterator i; + ControllerBindingCollection::iterator it; - for (i = mControllers->begin(); i != mControllers->end(); ++i) { - int irc = (*i)->stop(); - LOGD("Controller '%s' stop rc = %d", (*i)->getName(), irc); + for (it = mControllerBindings->begin(); it != mControllerBindings->end(); ++it) { + int irc = (*it)->getController()->stop(); if (irc && !rc) rc = irc; } return rc; } +NetworkManager::ControllerBinding *NetworkManager::lookupBinding(Controller *c) { + ControllerBindingCollection::iterator it; + + for (it = mControllerBindings->begin(); it != mControllerBindings->end(); ++it) { + if ((*it)->getController() == c) + return (*it); + } + errno = ENOENT; + return NULL; +} + Controller *NetworkManager::findController(const char *name) { - ControllerCollection::iterator i; - for (i = mControllers->begin(); i != mControllers->end(); ++i) { - if (!strcmp((*i)->getName(), name)) - return *i; + ControllerBindingCollection::iterator it; + + for (it = mControllerBindings->begin(); it != mControllerBindings->end(); ++it) { + if (!strcasecmp((*it)->getController()->getName(), name)) + return (*it)->getController(); } - LOGW("Controller '%s' not found", name); + errno = ENOENT; return NULL; } -void NetworkManager::onInterfaceConnected(Controller *c, const InterfaceConfig *cfg) { +void NetworkManager::onInterfaceConnected(Controller *c) { LOGD("Controller %s interface %s connected", c->getName(), c->getBoundInterface()); - // Look up the interface - - if (0) { // already started? + if (mDhcp->start(c)) { + LOGE("Failed to start DHCP (%s)", strerror(errno)); + return; } +} - if (cfg) { - if (cfg->getUseDhcp() && mDhcp->start(c->getBoundInterface())) { - LOGE("DHCP start failed"); - } else if (!cfg->getUseDhcp()) { - // Static configuration - } - } else { - LOGD("No InterfaceConfig for %s:%s - assuming self-managed", - c->getName(), c->getBoundInterface()); - } +void NetworkManager::onInterfaceDisconnected(Controller *c) { + LOGD("Controller %s interface %s disconnected", c->getName(), + c->getBoundInterface()); + + mDhcp->stop(); } -void NetworkManager::onInterfaceDisconnected(Controller *c, const char *name) { - LOGD("Controller %s interface %s disconnected", c->getName(), name); +void NetworkManager::onControllerSuspending(Controller *c) { + LOGD("Controller %s interface %s suspending", c->getName(), + c->getBoundInterface()); + mDhcp->stop(); +} + +void NetworkManager::onControllerResumed(Controller *c) { + LOGD("Controller %s interface %s resumed", c->getName(), + c->getBoundInterface()); +} - // If we have a DHCP request out on this interface then stop it - if (1) { - mDhcp->stop(); +void NetworkManager::onDhcpStateChanged(Controller *c, int state) { + char tmp[255]; + char tmp2[255]; + + LOGD("onDhcpStateChanged(%s -> %s)", + DhcpState::toString(mLastDhcpState, tmp, sizeof(tmp)), + DhcpState::toString(state, tmp2, sizeof(tmp2))); + + switch(state) { + case DhcpState::BOUND: + // Refresh the 'net.xxx' for the controller + break; + case DhcpState::RENEWING: + break; + default: + break; } + + char *tmp3; + asprintf(&tmp3, + "DHCP state changed from %d (%s) -> %d (%s)", + mLastDhcpState, + DhcpState::toString(mLastDhcpState, tmp, sizeof(tmp)), + state, + DhcpState::toString(state, tmp2, sizeof(tmp2))); + + getBroadcaster()->sendBroadcast(ResponseCode::DhcpStateChange, + tmp3, + false); + free(tmp3); + + mLastDhcpState = state; +} + +void NetworkManager::onDhcpEvent(Controller *c, int evt) { + char tmp[64]; + LOGD("onDhcpEvent(%s)", DhcpEvent::toString(evt, tmp, sizeof(tmp))); +} + +void NetworkManager::onDhcpLeaseUpdated(Controller *c, struct in_addr *addr, + struct in_addr *net, + struct in_addr *brd, + struct in_addr *gw, + struct in_addr *dns1, + struct in_addr *dns2) { + ControllerBinding *bind = lookupBinding(c); + + if (!bind->getCurrentCfg()) + bind->setCurrentCfg(new InterfaceConfig(true)); + + bind->getCurrentCfg()->setIp(addr); + bind->getCurrentCfg()->setNetmask(net); + bind->getCurrentCfg()->setGateway(gw); + bind->getCurrentCfg()->setBroadcast(brd); + bind->getCurrentCfg()->setDns(0, dns1); + bind->getCurrentCfg()->setDns(1, dns2); +} + +NetworkManager::ControllerBinding::ControllerBinding(Controller *c) : + mController(c) { +} + +void NetworkManager::ControllerBinding::setCurrentCfg(InterfaceConfig *c) { + mCurrentCfg = c; } + +void NetworkManager::ControllerBinding::setBoundCfg(InterfaceConfig *c) { + mBoundCfg = c; +} + diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h index 44f3417fd22..93702ce8ded 100644 --- a/nexus/NetworkManager.h +++ b/nexus/NetworkManager.h @@ -17,6 +17,7 @@ #ifndef _NETWORKMANAGER_H #define _NETWORKMANAGER_H +#include #include #include "Controller.h" @@ -28,14 +29,33 @@ class InterfaceConfig; class DhcpClient; class NetworkManager : public IControllerHandler, public IDhcpEventHandlers { -private: static NetworkManager *sInstance; + class ControllerBinding { + Controller *mController; + InterfaceConfig *mCurrentCfg; + InterfaceConfig *mBoundCfg; + + public: + ControllerBinding(Controller *c); + virtual ~ControllerBinding() {} + + InterfaceConfig *getCurrentCfg() { return mCurrentCfg; } + InterfaceConfig *getBoundCfg() { return mCurrentCfg; } + Controller *getController() { return mController; } + + void setCurrentCfg(InterfaceConfig *cfg); + void setBoundCfg(InterfaceConfig *cfg); + }; + + typedef android::List ControllerBindingCollection; + private: - ControllerCollection *mControllers; - SocketListener *mBroadcaster; - PropertyManager *mPropMngr; - DhcpClient *mDhcp; + ControllerBindingCollection *mControllerBindings; + SocketListener *mBroadcaster; + PropertyManager *mPropMngr; + DhcpClient *mDhcp; + int mLastDhcpState; public: virtual ~NetworkManager(); @@ -57,8 +77,19 @@ class NetworkManager : public IControllerHandler, public IDhcpEventHandlers { int stopControllers(); NetworkManager(PropertyManager *propMngr); + ControllerBinding *lookupBinding(Controller *c); + + void onInterfaceConnected(Controller *c); + void onInterfaceDisconnected(Controller *c); + void onControllerSuspending(Controller *c); + void onControllerResumed(Controller *c); - void onInterfaceConnected(Controller *c, const InterfaceConfig *cfg); - void onInterfaceDisconnected(Controller *c, const char *name); + void onDhcpStateChanged(Controller *c, int state); + void onDhcpEvent(Controller *c, int event); + void onDhcpLeaseUpdated(Controller *c, + struct in_addr *addr, struct in_addr *net, + struct in_addr *brd, + struct in_addr *gw, struct in_addr *dns1, + struct in_addr *dns2); }; #endif diff --git a/nexus/Property.cpp b/nexus/Property.cpp new file mode 100644 index 00000000000..d02769d57fa --- /dev/null +++ b/nexus/Property.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#define LOG_TAG "Property" + +#include + +#include "Property.h" + +Property::Property(const char *name, bool readOnly, + int type, int numElements) : + mName(name), mReadOnly(readOnly), mType(type), + mNumElements(numElements) { + if (index(name, '.')) { + LOGW("Property name %s violates namespace rules", name); + } +} + +StringProperty::StringProperty(const char *name, bool ro, int elements) : + Property(name, ro, Property::Type_STRING, elements) { +} +int StringProperty::set(int idx, int value) { + LOGE("Integer 'set' called on string property!"); + errno = EINVAL; + return -1; +} +int StringProperty::set(int idx, struct in_addr *value) { + LOGE("IpAddr 'set' called on string property!"); + errno = EINVAL; + return -1; +} +int StringProperty::get(int idx, int *buffer) { + LOGE("Integer 'get' called on string property!"); + errno = EINVAL; + return -1; +} +int StringProperty::get(int idx, struct in_addr *buffer) { + LOGE("IpAddr 'get' called on string property!"); + errno = EINVAL; + return -1; +} + +StringPropertyHelper::StringPropertyHelper(const char *name, bool ro, + char *buffer, size_t max) : + StringProperty(name, ro, 1) { + mBuffer = buffer; + mMax = max; +} + +int StringPropertyHelper::set(int idx, const char *value) { + if (idx != 0) { + LOGW("Attempt to use array index on StringPropertyHelper::set"); + errno = EINVAL; + return -1; + } + strncpy(mBuffer, value, mMax); + return 0; +} + +int StringPropertyHelper::get(int idx, char *buffer, size_t max) { + if (idx != 0) { + LOGW("Attempt to use array index on StringPropertyHelper::get"); + errno = EINVAL; + return -1; + } + strncpy(buffer, mBuffer, max); + return 0; +} + +IntegerProperty::IntegerProperty(const char *name, bool ro, int elements) : + Property(name, ro, Property::Type_INTEGER, elements) { +} + +int IntegerProperty::set(int idx, const char *value) { + LOGE("String 'set' called on integer property!"); + errno = EINVAL; + return -1; +} +int IntegerProperty::set(int idx, struct in_addr *value) { + LOGE("IpAddr 'set' called on integer property!"); + errno = EINVAL; + return -1; +} +int IntegerProperty::get(int idx, char *buffer, size_t max) { + LOGE("String 'get' called on integer property!"); + errno = EINVAL; + return -1; +} +int IntegerProperty::get(int idx, struct in_addr *buffer) { + LOGE("IpAddr 'get' called on integer property!"); + errno = EINVAL; + return -1; +} + +IntegerPropertyHelper::IntegerPropertyHelper(const char *name, bool ro, + int *buffer) : + IntegerProperty(name, ro, 1) { + mBuffer = buffer; +} + +int IntegerPropertyHelper::set(int idx, int value) { + if (idx != 0) { + LOGW("Attempt to use array index on IntegerPropertyHelper::set"); + errno = EINVAL; + return -1; + } + *mBuffer = value; + return 0; +} + +int IntegerPropertyHelper::get(int idx, int *buffer) { + if (idx != 0) { + LOGW("Attempt to use array index on IntegerPropertyHelper::get"); + errno = EINVAL; + return -1; + } + *buffer = *mBuffer; + return 0; +} + +IPV4AddressProperty::IPV4AddressProperty(const char *name, bool ro, int elements) : + Property(name, ro, Property::Type_IPV4, elements) { +} + +int IPV4AddressProperty::set(int idx, const char *value) { + LOGE("String 'set' called on ipv4 property!"); + errno = EINVAL; + return -1; +} +int IPV4AddressProperty::set(int idx, int value) { + LOGE("Integer 'set' called on ipv4 property!"); + errno = EINVAL; + return -1; +} +int IPV4AddressProperty::get(int idx, char *buffer, size_t max) { + LOGE("String 'get' called on ipv4 property!"); + errno = EINVAL; + return -1; +} +int IPV4AddressProperty::get(int idx, int *buffer) { + LOGE("Integer 'get' called on ipv4 property!"); + errno = EINVAL; + return -1; +} + +IPV4AddressPropertyHelper::IPV4AddressPropertyHelper(const char *name, bool ro, + struct in_addr *buffer) : + IPV4AddressProperty(name, ro, 1) { + mBuffer = buffer; +} + +int IPV4AddressPropertyHelper::set(int idx, struct in_addr *value) { + if (idx != 0) { + LOGW("Attempt to use array index on IPV4AddressPropertyHelper::set"); + errno = EINVAL; + return -1; + } + memcpy(mBuffer, value, sizeof(struct in_addr)); + return 0; +} + +int IPV4AddressPropertyHelper::get(int idx, struct in_addr *buffer) { + if (idx != 0) { + LOGW("Attempt to use array index on IPV4AddressPropertyHelper::get"); + errno = EINVAL; + return -1; + } + memcpy(buffer, mBuffer, sizeof(struct in_addr)); + return 0; +} + +PropertyNamespace::PropertyNamespace(const char *name) { + mName = strdup(name); + mProperties = new PropertyCollection(); +} + +PropertyNamespace::~PropertyNamespace() { + PropertyCollection::iterator it; + for (it = mProperties->begin(); it != mProperties->end();) { + delete (*it); + it = mProperties->erase(it); + } + delete mProperties; + free(mName); +} diff --git a/nexus/Property.h b/nexus/Property.h index 198f7223ca7..ceea2d3e3ce 100644 --- a/nexus/Property.h +++ b/nexus/Property.h @@ -14,8 +14,124 @@ * limitations under the License. */ +#ifndef _PROPERTY_H +#define _PROPERTY_H + +#include +#include + class Property { + const char *mName; + bool mReadOnly; + int mType; + int mNumElements; + public: - static const int NameMaxSize = 128; + static const int NameMaxSize = 128; static const int ValueMaxSize = 255; + + static const int Type_STRING = 1; + static const int Type_INTEGER = 2; + static const int Type_IPV4 = 3; + + Property(const char *name, bool ro, int type, int elements); + virtual ~Property() {} + + virtual int set(int idx, const char *value) = 0; + virtual int set(int idx, int value) = 0; + virtual int set(int idx, struct in_addr *value) = 0; + + virtual int get(int idx, char *buffer, size_t max) = 0; + virtual int get(int idx, int *buffer) = 0; + virtual int get(int idx, struct in_addr *buffer) = 0; + + int getType() { return mType; } + bool getReadOnly() { return mReadOnly; } + int getNumElements() { return mNumElements; } + const char *getName() { return mName; } +}; + +class StringProperty : public Property { +public: + StringProperty(const char *name, bool ro, int elements); + virtual ~StringProperty() {} + + virtual int set(int idx, const char *value) = 0; + int set(int idx, int value); + int set(int idx, struct in_addr *value); + + virtual int get(int idx, char *buffer, size_t max) = 0; + int get(int idx, int *buffer); + int get(int idx, struct in_addr *buffer); +}; + +class StringPropertyHelper : public StringProperty { + char *mBuffer; + size_t mMax; +public: + StringPropertyHelper(const char *name, bool ro, + char *buffer, size_t max); + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); +}; + +class IntegerProperty : public Property { +public: + IntegerProperty(const char *name, bool ro, int elements); + virtual ~IntegerProperty() {} + + int set(int idx, const char *value); + virtual int set(int idx, int value) = 0; + int set(int idx, struct in_addr *value); + + int get(int idx, char *buffer, size_t max); + virtual int get(int idx, int *buffer) = 0; + int get(int idx, struct in_addr *buffer); +}; + +class IntegerPropertyHelper : public IntegerProperty { + int *mBuffer; +public: + IntegerPropertyHelper(const char *name, bool ro, int *buffer); + int set(int idx, int value); + int get(int idx, int *buffer); +}; + +class IPV4AddressProperty : public Property { +public: + IPV4AddressProperty(const char *name, bool ro, int elements); + virtual ~IPV4AddressProperty() {} + + int set(int idx, const char *value); + int set(int idx, int value); + virtual int set(int idx, struct in_addr *value) = 0; + + int get(int idx, char *buffer, size_t max); + int get(int idx, int *buffer); + virtual int get(int idx, struct in_addr *buffer) = 0; +}; + +class IPV4AddressPropertyHelper : public IPV4AddressProperty { + struct in_addr *mBuffer; +public: + IPV4AddressPropertyHelper(const char *name, bool ro, struct in_addr *buf); + int set(int idx, struct in_addr *value); + int get(int idx, struct in_addr *buffer); }; + +typedef android::List PropertyCollection; + +class PropertyNamespace { + char *mName; + PropertyCollection *mProperties; + +public: + PropertyNamespace(const char *name); + virtual ~PropertyNamespace(); + + const char *getName() { return mName; } + PropertyCollection *getProperties() { return mProperties; } +}; + +typedef android::List PropertyNamespaceCollection; +#endif diff --git a/nexus/PropertyManager.cpp b/nexus/PropertyManager.cpp index 6faf9b8302d..704b2230b6a 100644 --- a/nexus/PropertyManager.cpp +++ b/nexus/PropertyManager.cpp @@ -14,6 +14,11 @@ * limitations under the License. */ +#include +#include +#include +#include + #define LOG_TAG "PropertyManager" #include @@ -21,103 +26,255 @@ #include "PropertyManager.h" PropertyManager::PropertyManager() { - mPropertyPairs = new PropertyPairCollection(); + mNamespaces = new PropertyNamespaceCollection(); pthread_mutex_init(&mLock, NULL); } PropertyManager::~PropertyManager() { - delete mPropertyPairs; + PropertyNamespaceCollection::iterator it; + + for (it = mNamespaces->begin(); it != mNamespaces->end();) { + delete (*it); + it = mNamespaces->erase(it); + } + delete mNamespaces; +} + +PropertyNamespace *PropertyManager::lookupNamespace_UNLOCKED(const char *ns) { + PropertyNamespaceCollection::iterator ns_it; + + for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { + if (!strcasecmp(ns, (*ns_it)->getName())) + return (*ns_it); + } + errno = ENOENT; + return NULL; } -int PropertyManager::registerProperty(const char *name, IPropertyProvider *pp) { - PropertyPairCollection::iterator it; +Property *PropertyManager::lookupProperty_UNLOCKED(PropertyNamespace *ns, const char *name) { + PropertyCollection::iterator it; -// LOGD("registerProperty(%s)", name); + for (it = ns->getProperties()->begin(); + it != ns->getProperties()->end(); ++it) { + if (!strcasecmp(name, (*it)->getName())) + return (*it); + } + errno = ENOENT; + return NULL; +} + +int PropertyManager::attachProperty(const char *ns_name, Property *p) { + PropertyNamespace *ns; + + LOGD("Attaching property %s to namespace %s", p->getName(), ns_name); pthread_mutex_lock(&mLock); - for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) { - if (!strcmp(name, (*it)->getName())) { - errno = EADDRINUSE; - LOGE("Failed to register property %s (%s)", - name, strerror(errno)); - pthread_mutex_unlock(&mLock); - return -1; - } + if (!(ns = lookupNamespace_UNLOCKED(ns_name))) { + LOGD("Creating namespace %s", ns_name); + ns = new PropertyNamespace(ns_name); + mNamespaces->push_back(ns); + } + + if (lookupProperty_UNLOCKED(ns, p->getName())) { + errno = EADDRINUSE; + pthread_mutex_unlock(&mLock); + LOGE("Failed to register property %s.%s (%s)", + ns_name, p->getName(), strerror(errno)); + return -1; } - mPropertyPairs->push_back(new PropertyPair(name, pp)); + + ns->getProperties()->push_back(p); pthread_mutex_unlock(&mLock); return 0; } -int PropertyManager::unregisterProperty(const char *name) { - PropertyPairCollection::iterator it; +int PropertyManager::detachProperty(const char *ns_name, Property *p) { + PropertyNamespace *ns; -// LOGD("unregisterProperty(%s)", name); + LOGD("Detaching property %s from namespace %s", p->getName(), ns_name); pthread_mutex_lock(&mLock); - for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) { - if (!strcmp(name, (*it)->getName())) { + if (!(ns = lookupNamespace_UNLOCKED(ns_name))) { + pthread_mutex_unlock(&mLock); + LOGE("Namespace '%s' not found", ns_name); + return -1; + } + + PropertyCollection::iterator it; + + for (it = ns->getProperties()->begin(); + it != ns->getProperties()->end(); ++it) { + if (!strcasecmp(p->getName(), (*it)->getName())) { delete ((*it)); - mPropertyPairs->erase(it); + ns->getProperties()->erase(it); pthread_mutex_unlock(&mLock); return 0; } } + + LOGE("Property %s.%s not found", ns_name, p->getName()); pthread_mutex_unlock(&mLock); errno = ENOENT; return -1; } +int PropertyManager::doSet(Property *p, int idx, const char *value) { + + if (p->getReadOnly()) { + errno = EROFS; + return -1; + } + + if (p->getType() == Property::Type_STRING) { + return p->set(idx, value); + } else if (p->getType() == Property::Type_INTEGER) { + int tmp; + errno = 0; + tmp = strtol(value, (char **) NULL, 10); + if (errno) { + LOGE("Failed to convert '%s' to int", value); + errno = EINVAL; + return -1; + } + return p->set(idx, tmp); + } else if (p->getType() == Property::Type_IPV4) { + struct in_addr tmp; + if (!inet_aton(value, &tmp)) { + LOGE("Failed to convert '%s' to ipv4", value); + errno = EINVAL; + return -1; + } + return p->set(idx, &tmp); + } else { + LOGE("Property '%s' has an unknown type (%d)", p->getName(), + p->getType()); + errno = EINVAL; + return -1; + } + errno = ENOENT; + return -1; +} + +int PropertyManager::doGet(Property *p, int idx, char *buffer, size_t max) { + + if (p->getType() == Property::Type_STRING) { + if (p->get(idx, buffer, max)) { + LOGW("String property %s get failed (%s)", p->getName(), + strerror(errno)); + return -1; + } + } + else if (p->getType() == Property::Type_INTEGER) { + int tmp; + if (p->get(idx, &tmp)) { + LOGW("Integer property %s get failed (%s)", p->getName(), + strerror(errno)); + return -1; + } + snprintf(buffer, max, "%d", tmp); + } else if (p->getType() == Property::Type_IPV4) { + struct in_addr tmp; + if (p->get(idx, &tmp)) { + LOGW("IPV4 property %s get failed (%s)", p->getName(), + strerror(errno)); + return -1; + } + strncpy(buffer, inet_ntoa(tmp), max); + } else { + LOGE("Property '%s' has an unknown type (%d)", p->getName(), + p->getType()); + errno = EINVAL; + return -1; + } + return 0; +} + /* * IPropertyManager methods */ int PropertyManager::set(const char *name, const char *value) { - PropertyPairCollection::iterator it; + LOGD("set %s = '%s'", name, value); pthread_mutex_lock(&mLock); - for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) { - if (!strcmp(name, (*it)->getName())) { - pthread_mutex_unlock(&mLock); - return (*it)->getProvider()->set(name, value); + PropertyNamespaceCollection::iterator ns_it; + for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { + PropertyCollection::iterator p_it; + for (p_it = (*ns_it)->getProperties()->begin(); + p_it != (*ns_it)->getProperties()->end(); ++p_it) { + for (int i = 0; i < (*p_it)->getNumElements(); i++) { + char fqn[255]; + char tmp[8]; + sprintf(tmp, "_%d", i); + snprintf(fqn, sizeof(fqn), "%s.%s%s", + (*ns_it)->getName(), (*p_it)->getName(), + ((*p_it)->getNumElements() > 1 ? tmp : "")); + if (!strcasecmp(name, fqn)) { + pthread_mutex_unlock(&mLock); + return doSet((*p_it), i, value); + } + } } } + + LOGE("Property %s not found", name); pthread_mutex_unlock(&mLock); errno = ENOENT; return -1; } const char *PropertyManager::get(const char *name, char *buffer, size_t max) { - PropertyPairCollection::iterator it; - - memset(buffer, 0, max); pthread_mutex_lock(&mLock); - for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) { - if (!strcmp(name, (*it)->getName())) { - pthread_mutex_unlock(&mLock); - return (*it)->getProvider()->get(name, buffer, max); + PropertyNamespaceCollection::iterator ns_it; + for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { + PropertyCollection::iterator p_it; + for (p_it = (*ns_it)->getProperties()->begin(); + p_it != (*ns_it)->getProperties()->end(); ++p_it) { + + for (int i = 0; i < (*p_it)->getNumElements(); i++) { + char fqn[255]; + char tmp[8]; + sprintf(tmp, "_%d", i); + snprintf(fqn, sizeof(fqn), "%s.%s%s", + (*ns_it)->getName(), (*p_it)->getName(), + ((*p_it)->getNumElements() > 1 ? tmp : "")); + if (!strcasecmp(name, fqn)) { + pthread_mutex_unlock(&mLock); + if (doGet((*p_it), i, buffer, max)) + return NULL; + return buffer; + } } + } } + + LOGE("Property %s not found", name); pthread_mutex_unlock(&mLock); errno = ENOENT; return NULL; } -android::List *PropertyManager::createPropertyList() { +android::List *PropertyManager::createPropertyList(const char *prefix) { android::List *c = new android::List(); - PropertyPairCollection::iterator it; - pthread_mutex_lock(&mLock); - for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) - c->push_back(strdup((*it)->getName())); + PropertyNamespaceCollection::iterator ns_it; + for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { + PropertyCollection::iterator p_it; + for (p_it = (*ns_it)->getProperties()->begin(); + p_it != (*ns_it)->getProperties()->end(); ++p_it) { + for (int i = 0; i < (*p_it)->getNumElements(); i++) { + char fqn[255]; + char tmp[8]; + sprintf(tmp, "_%d", i); + snprintf(fqn, sizeof(fqn), "%s.%s%s", + (*ns_it)->getName(), (*p_it)->getName(), + ((*p_it)->getNumElements() > 1 ? tmp : "")); + if (!prefix || + (prefix && !strncasecmp(fqn, prefix, strlen(prefix)))) { + c->push_back(strdup(fqn)); + } + } + } + } pthread_mutex_unlock(&mLock); return c; } - -PropertyPair::PropertyPair(const char *name, IPropertyProvider *pp) { - mName = strdup(name); - mPp = pp; -} - -PropertyPair::~PropertyPair() { - free(mName); -} diff --git a/nexus/PropertyManager.h b/nexus/PropertyManager.h index 10d0b2aa9a0..af56a9c1560 100644 --- a/nexus/PropertyManager.h +++ b/nexus/PropertyManager.h @@ -22,36 +22,28 @@ #include -#include "IPropertyProvider.h" - -class PropertyPair { -private: - char *mName; - IPropertyProvider *mPp; - -public: - PropertyPair(const char *name, IPropertyProvider *pp); - virtual ~PropertyPair(); - - const char *getName() { return mName; } - IPropertyProvider *getProvider() { return mPp; } -}; - -typedef android::List PropertyPairCollection; +#include "Property.h" class PropertyManager { - PropertyPairCollection *mPropertyPairs; - pthread_mutex_t mLock; + PropertyNamespaceCollection *mNamespaces; + pthread_mutex_t mLock; public: PropertyManager(); - virtual ~PropertyManager(); - int registerProperty(const char *name, IPropertyProvider *pp); - int unregisterProperty(const char *name); - android::List *createPropertyList(); + virtual ~PropertyManager(); + int attachProperty(const char *ns, Property *p); + int detachProperty(const char *ns, Property *p); + + android::List *createPropertyList(const char *prefix); int set(const char *name, const char *value); const char *get(const char *name, char *buffer, size_t max); + +private: + PropertyNamespace *lookupNamespace_UNLOCKED(const char *ns); + Property *lookupProperty_UNLOCKED(PropertyNamespace *ns, const char *name); + int doSet(Property *p, int idx, const char *value); + int doGet(Property *p, int idx, char *buffer, size_t max); }; #endif diff --git a/nexus/ErrorCode.h b/nexus/ResponseCode.h similarity index 84% rename from nexus/ErrorCode.h rename to nexus/ResponseCode.h index 414dd2c5a05..4b6cac85199 100644 --- a/nexus/ErrorCode.h +++ b/nexus/ResponseCode.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef _ERRORCODE_H -#define _ERRORCODE_H +#ifndef _RESPONSECODE_H +#define _RESPONSECODE_H -class ErrorCode { +class ResponseCode { public: // 100 series - Requestion action was initiated; expect another reply // before proceeding with a new command. @@ -44,5 +44,10 @@ class ErrorCode { // 600 series - Unsolicited broadcasts static const int UnsolicitedInformational = 600; + static const int DhcpStateChange = 605; + static const int SupplicantStateChange = 610; + static const int ScanResultsReady = 615; + static const int LinkSpeedChange = 620; + static const int RssiChange = 625; }; #endif diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp index 9bb6bf2c182..6aa36e87590 100644 --- a/nexus/Supplicant.cpp +++ b/nexus/Supplicant.cpp @@ -30,7 +30,6 @@ #include "Supplicant.h" #include "SupplicantListener.h" #include "NetworkManager.h" -#include "ErrorCode.h" #include "WifiController.h" #include "SupplicantStatus.h" @@ -114,6 +113,29 @@ bool Supplicant::isStarted() { return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME); } +int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len) { + + if (!mCtrl) { + errno = ENOTCONN; + return -1; + } + +// LOGD("sendCommand(): -> '%s'", cmd); + + int rc; + memset(reply, 0, *reply_len); + if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) { + errno = ETIMEDOUT; + return -1; + } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) { + strcpy(reply, "FAIL"); + errno = EIO; + return -1; + } + + // LOGD("sendCommand(): <- '%s'", reply); + return 0; +} SupplicantStatus *Supplicant::getStatus() { char *reply; size_t len = 4096; @@ -162,6 +184,7 @@ int Supplicant::refreshNetworkList() { return -1; } + PropertyManager *pm = NetworkManager::Instance()->getPropMngr(); pthread_mutex_lock(&mNetworksLock); int num_added = 0; @@ -182,7 +205,9 @@ int Supplicant::refreshNetworkList() { delete new_wn; } else { num_added++; - new_wn->registerProperties(); + char new_ns[20]; + snprintf(new_ns, sizeof(new_ns), "wifi.net.%d", new_wn->getNetworkId()); + new_wn->attachProperties(pm, new_ns); mNetworks->push_back(new_wn); if (new_wn->refresh()) { LOGW("Unable to refresh network id %d (%s)", @@ -198,7 +223,9 @@ int Supplicant::refreshNetworkList() { for (i = mNetworks->begin(); i != mNetworks->end(); ++i) { if (0) { num_removed++; - (*i)->unregisterProperties(); + char del_ns[20]; + snprintf(del_ns, sizeof(del_ns), "wifi.net.%d", (*i)->getNetworkId()); + (*i)->detachProperties(pm, del_ns); delete (*i); i = mNetworks->erase(i); } @@ -247,44 +274,98 @@ int Supplicant::connectToSupplicant() { return 0; } -int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len) -{ - if (!mCtrl) { - errno = ENOTCONN; +int Supplicant::setScanMode(bool active) { + char reply[255]; + size_t len = sizeof(reply); + + if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"), + reply, &len)) { + LOGW("triggerScan(%d): Error setting scan mode (%s)", active, + strerror(errno)); return -1; } + return 0; +} -// LOGD("sendCommand(): -> '%s'", cmd); +int Supplicant::triggerScan() { + char reply[255]; + size_t len = sizeof(reply); - int rc; - memset(reply, 0, *reply_len); - if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) { - errno = ETIMEDOUT; + if (sendCommand("SCAN", reply, &len)) { + LOGW("triggerScan(): Error initiating scan"); return -1; - } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) { - strcpy(reply, "FAIL"); - errno = EIO; + } + return 0; +} + +int Supplicant::getRssi(int *buffer) { + char reply[64]; + size_t len = sizeof(reply); + + if (sendCommand("DRIVER RSSI", reply, &len)) { + LOGW("Failed to get RSSI (%s)", strerror(errno)); return -1; } -// LOGD("sendCommand(): <- '%s'", reply); + char *next = reply; + char *s; + for (int i = 0; i < 3; i++) { + if (!(s = strsep(&next, " "))) { + LOGE("Error parsing RSSI"); + errno = EIO; + return -1; + } + } + *buffer = atoi(s); return 0; } -int Supplicant::triggerScan(bool active) { - char reply[255]; +int Supplicant::getLinkSpeed() { + char reply[64]; size_t len = sizeof(reply); - if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"), - reply, &len)) { - LOGW("triggerScan(%d): Error setting scan mode (%s)", active, - strerror(errno)); + if (sendCommand("DRIVER LINKSPEED", reply, &len)) { + LOGW("Failed to get LINKSPEED (%s)", strerror(errno)); return -1; } - len = sizeof(reply); - if (sendCommand("SCAN", reply, &len)) { - LOGW("triggerScan(%d): Error initiating scan", active); + char *next = reply; + char *s; + + if (!(s = strsep(&next, " "))) { + LOGE("Error parsing LINKSPEED"); + errno = EIO; + return -1; + } + + if (!(s = strsep(&next, " "))) { + LOGE("Error parsing LINKSPEED"); + errno = EIO; + return -1; + } + return atoi(s); +} + +int Supplicant::stopDriver() { + char reply[64]; + size_t len = sizeof(reply); + + LOGD("stopDriver()"); + + if (sendCommand("DRIVER STOP", reply, &len)) { + LOGW("Failed to stop driver (%s)", strerror(errno)); + return -1; + } + return 0; +} + +int Supplicant::startDriver() { + char reply[64]; + size_t len = sizeof(reply); + + LOGD("startDriver()"); + if (sendCommand("DRIVER START", reply, &len)) { + LOGW("Failed to start driver (%s)", strerror(errno)); return -1; } return 0; @@ -301,7 +382,11 @@ WifiNetwork *Supplicant::createNetwork() { reply[strlen(reply) -1] = '\0'; WifiNetwork *wn = new WifiNetwork(mController, this, atoi(reply)); + PropertyManager *pm = NetworkManager::Instance()->getPropMngr(); pthread_mutex_lock(&mNetworksLock); + char new_ns[20]; + snprintf(new_ns, sizeof(new_ns), "wifi.net.%d", wn->getNetworkId()); + wn->attachProperties(pm, new_ns); mNetworks->push_back(wn); pthread_mutex_unlock(&mNetworksLock); return wn; @@ -411,8 +496,9 @@ int Supplicant::setNetworkVar(int networkId, const char *var, const char *val) { char reply[255]; size_t len = sizeof(reply) -1; + LOGD("netid %d, var '%s' = '%s'", networkId, var, val); char *tmp; - asprintf(&tmp, "SET_NETWORK %d %s \"%s\"", networkId, var, val); + asprintf(&tmp, "SET_NETWORK %d %s %s", networkId, var, val); if (sendCommand(tmp, reply, &len)) { free(tmp); return -1; @@ -457,6 +543,95 @@ int Supplicant::enableNetwork(int networkId, bool enabled) { return 0; } +int Supplicant::enablePacketFilter() { + char req[128]; + char reply[16]; + size_t len; + int i; + + for (i = 0; i <=3; i++) { + snprintf(req, sizeof(req), "DRIVER RXFILTER-ADD %d", i); + len = sizeof(reply); + if (sendCommand(req, reply, &len)) + return -1; + } + + len = sizeof(reply); + if (sendCommand("DRIVER RXFILTER-START", reply, &len)) + return -1; + return 0; +} + +int Supplicant::disablePacketFilter() { + char req[128]; + char reply[16]; + size_t len; + int i; + + len = sizeof(reply); + if (sendCommand("DRIVER RXFILTER-STOP", reply, &len)) + return -1; + + for (i = 3; i >=0; i--) { + snprintf(req, sizeof(req), "DRIVER RXFILTER-REMOVE %d", i); + len = sizeof(reply); + if (sendCommand(req, reply, &len)) + return -1; + } + return 0; +} + +int Supplicant::enableBluetoothCoexistenceScan() { + char req[128]; + char reply[16]; + size_t len; + int i; + + len = sizeof(reply); + if (sendCommand("DRIVER BTCOEXSCAN-START", reply, &len)) + return -1; + return 0; +} + +int Supplicant::disableBluetoothCoexistenceScan() { + char req[128]; + char reply[16]; + size_t len; + int i; + + len = sizeof(reply); + if (sendCommand("DRIVER BTCOEXSCAN-STOP", reply, &len)) + return -1; + return 0; +} + +int Supplicant::setBluetoothCoexistenceMode(int mode) { + char req[64]; + + sprintf(req, "DRIVER BTCOEXMODE %d", mode); + + char reply[16]; + size_t len = sizeof(reply) -1; + + if (sendCommand(req, reply, &len)) + return -1; + return 0; +} + +int Supplicant::setApScanMode(int mode) { + char req[64]; + +// LOGD("setApScanMode(%d)", mode); + sprintf(req, "AP_SCAN %d", mode); + + char reply[16]; + size_t len = sizeof(reply) -1; + + if (sendCommand(req, reply, &len)) + return -1; + return 0; +} + int Supplicant::retrieveInterfaceName() { char reply[255]; @@ -469,3 +644,34 @@ int Supplicant::retrieveInterfaceName() { mInterfaceName = strdup(reply); return 0; } + +int Supplicant::reconnect() { + char req[128]; + char reply[16]; + size_t len; + int i; + + len = sizeof(reply); + if (sendCommand("RECONNECT", reply, &len)) + return -1; + return 0; +} + +int Supplicant::disconnect() { + char req[128]; + char reply[16]; + size_t len; + int i; + + len = sizeof(reply); + if (sendCommand("DISCONNECT", reply, &len)) + return -1; + return 0; +} + +int Supplicant::getNetworkCount() { + pthread_mutex_lock(&mNetworksLock); + int cnt = mNetworks->size(); + pthread_mutex_unlock(&mNetworksLock); + return cnt; +} diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h index 3efbe4cd401..3900f4f7fb1 100644 --- a/nexus/Supplicant.h +++ b/nexus/Supplicant.h @@ -30,7 +30,6 @@ class SupplicantStatus; #include "ISupplicantEventHandler.h" class Supplicant { -private: struct wpa_ctrl *mCtrl; struct wpa_ctrl *mMonitor; SupplicantListener *mListener; @@ -50,7 +49,8 @@ class Supplicant { int stop(); bool isStarted(); - int triggerScan(bool active); + int setScanMode(bool active); + int triggerScan(); WifiNetwork *createNetwork(); WifiNetwork *lookupNetwork(int networkId); @@ -63,6 +63,21 @@ class Supplicant { size_t max); int enableNetwork(int networkId, bool enabled); + int disconnect(); + int reconnect(); + int reassociate(); + int setApScanMode(int mode); + int enablePacketFilter(); + int disablePacketFilter(); + int setBluetoothCoexistenceMode(int mode); + int enableBluetoothCoexistenceScan(); + int disableBluetoothCoexistenceScan(); + int stopDriver(); + int startDriver(); + int getRssi(int *buffer); + int getLinkSpeed(); + int getNetworkCount(); + SupplicantStatus *getStatus(); Controller *getController() { return (Controller *) mController; } diff --git a/nexus/SupplicantState.cpp b/nexus/SupplicantState.cpp index a16d3709ece..2815430f9d7 100644 --- a/nexus/SupplicantState.cpp +++ b/nexus/SupplicantState.cpp @@ -23,25 +23,25 @@ char *SupplicantState::toString(int val, char *buffer, int max) { if (val == SupplicantState::UNKNOWN) - strncpy(buffer, "Unknown", max); + strncpy(buffer, "UNKNOWN", max); else if (val == SupplicantState::DISCONNECTED) - strncpy(buffer, "Disconnected", max); + strncpy(buffer, "DISCONNECTED", max); else if (val == SupplicantState::INACTIVE) - strncpy(buffer, "Inactive", max); + strncpy(buffer, "INACTIVE", max); else if (val == SupplicantState::SCANNING) - strncpy(buffer, "Scanning", max); + strncpy(buffer, "SCANNING", max); else if (val == SupplicantState::ASSOCIATING) - strncpy(buffer, "Associating", max); + strncpy(buffer, "ASSOCIATING", max); else if (val == SupplicantState::ASSOCIATED) - strncpy(buffer, "Associated", max); + strncpy(buffer, "ASSOCIATED", max); else if (val == SupplicantState::FOURWAY_HANDSHAKE) - strncpy(buffer, "Fourway Handshake", max); + strncpy(buffer, "FOURWAY_HANDSHAKE", max); else if (val == SupplicantState::GROUP_HANDSHAKE) - strncpy(buffer, "Group Handshake", max); + strncpy(buffer, "GROUP_HANDSHAKE", max); else if (val == SupplicantState::COMPLETED) - strncpy(buffer, "Completed", max); + strncpy(buffer, "COMPLETED", max); else if (val == SupplicantState::IDLE) - strncpy(buffer, "Idle", max); + strncpy(buffer, "IDLE", max); else strncpy(buffer, "(internal error)", max); diff --git a/nexus/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp index 61535c35685..016c790747a 100644 --- a/nexus/TiwlanWifiController.cpp +++ b/nexus/TiwlanWifiController.cpp @@ -51,6 +51,7 @@ int TiwlanWifiController::powerUp() { int TiwlanWifiController::powerDown() { if (mEventListener) { delete mEventListener; + shutdown(mListenerSock, SHUT_RDWR); close(mListenerSock); mListenerSock = -1; mEventListener = NULL; @@ -77,7 +78,8 @@ int TiwlanWifiController::loadFirmware() { LOGD("Firmware loaded OK"); if (startDriverEventListener()) { - LOGW("Failed to start driver event listener"); + LOGW("Failed to start driver event listener (%s)", + strerror(errno)); } return 0; @@ -95,32 +97,48 @@ int TiwlanWifiController::loadFirmware() { int TiwlanWifiController::startDriverEventListener() { struct sockaddr_in addr; - int s; - if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + if (mListenerSock != -1) { + LOGE("Listener already started!"); + errno = EBUSY; return -1; + } + + if ((mListenerSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + LOGE("socket failed (%s)", strerror(errno)); + return -1; + } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(TI_DRIVER_MSG_PORT); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(s); - return -1; + if (bind(mListenerSock, + (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + LOGE("bind failed (%s)", strerror(errno)); + goto out_err; } - mEventListener = new TiwlanEventListener(s); + mEventListener = new TiwlanEventListener(mListenerSock); if (mEventListener->startListener()) { LOGE("Error starting driver listener (%s)", strerror(errno)); + goto out_err; + } + return 0; +out_err: + if (mEventListener) { delete mEventListener; mEventListener = NULL; - close(s); - return -1; } - mListenerSock = s; - return 0; + if (mListenerSock != -1) { + shutdown(mListenerSock, SHUT_RDWR); + close(mListenerSock); + mListenerSock = -1; + } + return -1; } bool TiwlanWifiController::isFirmwareLoaded() { diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp index add4dc39a0a..015710fcc53 100644 --- a/nexus/VpnController.cpp +++ b/nexus/VpnController.cpp @@ -27,56 +27,66 @@ VpnController::VpnController(PropertyManager *propmngr, IControllerHandler *handlers) : - Controller("VPN", propmngr, handlers) { + Controller("vpn", propmngr, handlers) { mEnabled = false; + + mStaticProperties.propEnabled = new VpnEnabledProperty(this); + mDynamicProperties.propGateway = new IPV4AddressPropertyHelper("Gateway", + false, + &mGateway); } int VpnController::start() { - mPropMngr->registerProperty("vpn.enabled", this); + mPropMngr->attachProperty("vpn", mStaticProperties.propEnabled); return 0; } int VpnController::stop() { - mPropMngr->unregisterProperty("vpn.enabled"); + mPropMngr->detachProperty("vpn", mStaticProperties.propEnabled); return 0; } -int VpnController::set(const char *name, const char *value) { - if (!strcmp(name, "vpn.enabled")) { - int en = atoi(value); - int rc; - - if (en == mEnabled) - return 0; - rc = (en ? enable() : disable()); +VpnController::VpnIntegerProperty::VpnIntegerProperty(VpnController *c, + const char *name, + bool ro, + int elements) : + IntegerProperty(name, ro, elements) { + mVc = c; +} - if (!rc) { - mEnabled = en; - if (en) - mPropMngr->unregisterProperty("vpn.gateway"); - else - mPropMngr->unregisterProperty("vpn.gateway"); - } - return rc; - } if (!strcmp(name, "vpn.gateway")) { - if (!inet_aton(value, &mVpnGateway)) { - errno = EINVAL; - return -1; - } - return 0; - } +VpnController::VpnStringProperty::VpnStringProperty(VpnController *c, + const char *name, + bool ro, int elements) : + StringProperty(name, ro, elements) { + mVc = c; +} - return Controller::set(name, value); +VpnController::VpnIPV4AddressProperty::VpnIPV4AddressProperty(VpnController *c, + const char *name, + bool ro, int elements) : + IPV4AddressProperty(name, ro, elements) { + mVc = c; } -const char *VpnController::get(const char *name, char *buffer, size_t maxsize) { - if (!strcmp(name, "vpn.enabled")) { - snprintf(buffer, maxsize, "%d", mEnabled); - return buffer; - } if (!strcmp(name, "vpn.gateway")) { - snprintf(buffer, maxsize, "%s", inet_ntoa(mVpnGateway)); - return buffer; +VpnController::VpnEnabledProperty::VpnEnabledProperty(VpnController *c) : + VpnIntegerProperty(c, "Enabled", false, 1) { +} +int VpnController::VpnEnabledProperty::get(int idx, int *buffer) { + *buffer = mVc->mEnabled; + return 0; +} +int VpnController::VpnEnabledProperty::set(int idx, int value) { + int rc; + if (!value) { + mVc->mPropMngr->detachProperty("vpn", mVc->mDynamicProperties.propGateway); + rc = mVc->disable(); + } else { + rc = mVc->enable(); + if (!rc) { + mVc->mPropMngr->attachProperty("vpn", mVc->mDynamicProperties.propGateway); + } } - - return Controller::get(name, buffer, maxsize); + if (!rc) + mVc->mEnabled = value; + return rc; } diff --git a/nexus/VpnController.h b/nexus/VpnController.h index 1af4d9fbc4d..4bd86b54de0 100644 --- a/nexus/VpnController.h +++ b/nexus/VpnController.h @@ -24,11 +24,63 @@ class IControllerHandler; class VpnController : public Controller { + class VpnIntegerProperty : public IntegerProperty { + protected: + VpnController *mVc; + public: + VpnIntegerProperty(VpnController *c, const char *name, bool ro, + int elements); + virtual ~VpnIntegerProperty() {} + virtual int set(int idx, int value) = 0; + virtual int get(int idx, int *buffer) = 0; + }; + friend class VpnController::VpnIntegerProperty; + + class VpnStringProperty : public StringProperty { + protected: + VpnController *mVc; + public: + VpnStringProperty(VpnController *c, const char *name, bool ro, + int elements); + virtual ~VpnStringProperty() {} + virtual int set(int idx, const char *value) = 0; + virtual int get(int idx, char *buffer, size_t max) = 0; + }; + friend class VpnController::VpnStringProperty; + + class VpnIPV4AddressProperty : public IPV4AddressProperty { + protected: + VpnController *mVc; + public: + VpnIPV4AddressProperty(VpnController *c, const char *name, bool ro, + int elements); + virtual ~VpnIPV4AddressProperty() {} + virtual int set(int idx, struct in_addr *value) = 0; + virtual int get(int idx, struct in_addr *buffer) = 0; + }; + friend class VpnController::VpnIPV4AddressProperty; + + class VpnEnabledProperty : public VpnIntegerProperty { + public: + VpnEnabledProperty(VpnController *c); + virtual ~VpnEnabledProperty() {}; + int set(int idx, int value); + int get(int idx, int *buffer); + }; + bool mEnabled; /* * Gateway of the VPN server to connect to */ - struct in_addr mVpnGateway; + struct in_addr mGateway; + + struct { + VpnEnabledProperty *propEnabled; + } mStaticProperties; + + struct { + IPV4AddressPropertyHelper *propGateway; + } mDynamicProperties; public: VpnController(PropertyManager *propmngr, IControllerHandler *handlers); @@ -37,13 +89,9 @@ class VpnController : public Controller { virtual int start(); virtual int stop(); - virtual int set(const char *name, const char *value); - virtual const char *get(const char *name, char *buffer, size_t maxlen); - protected: virtual int enable() = 0; virtual int disable() = 0; - }; #endif diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp index ef5ecae17bc..c218c30ad79 100644 --- a/nexus/WifiController.cpp +++ b/nexus/WifiController.cpp @@ -23,9 +23,8 @@ #include "Supplicant.h" #include "WifiController.h" -#include "WifiScanner.h" #include "NetworkManager.h" -#include "ErrorCode.h" +#include "ResponseCode.h" #include "WifiNetwork.h" #include "ISupplicantEventHandler.h" #include "SupplicantState.h" @@ -37,11 +36,12 @@ #include "SupplicantStateChangeEvent.h" #include "SupplicantConnectionTimeoutEvent.h" #include "SupplicantDisconnectedEvent.h" +#include "WifiStatusPoller.h" WifiController::WifiController(PropertyManager *mPropMngr, IControllerHandler *handlers, char *modpath, char *modname, char *modargs) : - Controller("WIFI", mPropMngr, handlers) { + Controller("wifi", mPropMngr, handlers) { strncpy(mModulePath, modpath, sizeof(mModulePath)); strncpy(mModuleName, modname, sizeof(mModuleName)); strncpy(mModuleArgs, modargs, sizeof(mModuleArgs)); @@ -49,22 +49,59 @@ WifiController::WifiController(PropertyManager *mPropMngr, mLatestScanResults = new ScanResultCollection(); pthread_mutex_init(&mLatestScanResultsLock, NULL); - mSupplicant = new Supplicant(this, this); - mScanner = new WifiScanner(mSupplicant, 10); - mCurrentScanMode = 0; + pthread_mutex_init(&mLock, NULL); + mSupplicant = new Supplicant(this, this); + mActiveScan = false; mEnabled = false; + mScanOnly = false; + mPacketFilter = false; + mBluetoothCoexScan = false; + mBluetoothCoexMode = 0; + mCurrentlyConnectedNetworkId = -1; + mStatusPoller = new WifiStatusPoller(this); + mRssiEventThreshold = 5; + mLastLinkSpeed = 0; mSupplicantState = SupplicantState::UNKNOWN; + + mStaticProperties.propEnabled = new WifiEnabledProperty(this); + mStaticProperties.propScanOnly = new WifiScanOnlyProperty(this); + mStaticProperties.propAllowedChannels = new WifiAllowedChannelsProperty(this); + + mStaticProperties.propRssiEventThreshold = + new IntegerPropertyHelper("RssiEventThreshold", false, &mRssiEventThreshold); + + mDynamicProperties.propSupplicantState = new WifiSupplicantStateProperty(this); + mDynamicProperties.propActiveScan = new WifiActiveScanProperty(this); + mDynamicProperties.propInterface = new WifiInterfaceProperty(this); + mDynamicProperties.propSearching = new WifiSearchingProperty(this); + mDynamicProperties.propPacketFilter = new WifiPacketFilterProperty(this); + mDynamicProperties.propBluetoothCoexScan = new WifiBluetoothCoexScanProperty(this); + mDynamicProperties.propBluetoothCoexMode = new WifiBluetoothCoexModeProperty(this); + mDynamicProperties.propCurrentNetwork = new WifiCurrentNetworkProperty(this); + + mDynamicProperties.propRssi = new IntegerPropertyHelper("Rssi", true, &mLastRssi); + mDynamicProperties.propLinkSpeed = new IntegerPropertyHelper("LinkSpeed", true, &mLastLinkSpeed); + + mDynamicProperties.propSuspended = new WifiSuspendedProperty(this); + mDynamicProperties.propNetCount = new WifiNetCountProperty(this); + mDynamicProperties.propTriggerScan = new WifiTriggerScanProperty(this); } int WifiController::start() { - mPropMngr->registerProperty("wifi.enabled", this); + mPropMngr->attachProperty("wifi", mStaticProperties.propEnabled); + mPropMngr->attachProperty("wifi", mStaticProperties.propScanOnly); + mPropMngr->attachProperty("wifi", mStaticProperties.propAllowedChannels); + mPropMngr->attachProperty("wifi", mStaticProperties.propRssiEventThreshold); return 0; } int WifiController::stop() { - mPropMngr->unregisterProperty("wifi.enabled"); + mPropMngr->detachProperty("wifi", mStaticProperties.propEnabled); + mPropMngr->detachProperty("wifi", mStaticProperties.propScanOnly); + mPropMngr->detachProperty("wifi", mStaticProperties.propAllowedChannels); + mPropMngr->detachProperty("wifi", mStaticProperties.propRssiEventThreshold); return 0; } @@ -114,9 +151,21 @@ int WifiController::enable() { if (mSupplicant->refreshNetworkList()) LOGW("Error getting list of networks (%s)", strerror(errno)); - mPropMngr->registerProperty("wifi.supplicant.state", this); - mPropMngr->registerProperty("wifi.scanmode", this); - mPropMngr->registerProperty("wifi.interface", this); + LOGW("TODO: Set # of allowed regulatory channels!"); + + mPropMngr->attachProperty("wifi", mDynamicProperties.propSupplicantState); + mPropMngr->attachProperty("wifi", mDynamicProperties.propActiveScan); + mPropMngr->attachProperty("wifi", mDynamicProperties.propInterface); + mPropMngr->attachProperty("wifi", mDynamicProperties.propSearching); + mPropMngr->attachProperty("wifi", mDynamicProperties.propPacketFilter); + mPropMngr->attachProperty("wifi", mDynamicProperties.propBluetoothCoexScan); + mPropMngr->attachProperty("wifi", mDynamicProperties.propBluetoothCoexMode); + mPropMngr->attachProperty("wifi", mDynamicProperties.propCurrentNetwork); + mPropMngr->attachProperty("wifi", mDynamicProperties.propRssi); + mPropMngr->attachProperty("wifi", mDynamicProperties.propLinkSpeed); + mPropMngr->attachProperty("wifi", mDynamicProperties.propSuspended); + mPropMngr->attachProperty("wifi", mDynamicProperties.propNetCount); + mPropMngr->attachProperty("wifi", mDynamicProperties.propTriggerScan); LOGI("Enabled successfully"); return 0; @@ -135,17 +184,87 @@ int WifiController::enable() { return -1; } +bool WifiController::getSuspended() { + pthread_mutex_lock(&mLock); + bool r = mSuspended; + pthread_mutex_unlock(&mLock); + return r; +} + +int WifiController::setSuspend(bool suspend) { + + pthread_mutex_lock(&mLock); + if (suspend == mSuspended) { + LOGW("Suspended state already = %d", suspend); + pthread_mutex_unlock(&mLock); + return 0; + } + + if (suspend) { + mHandlers->onControllerSuspending(this); + + char tmp[80]; + LOGD("Suspending from supplicant state %s", + SupplicantState::toString(mSupplicantState, + tmp, + sizeof(tmp))); + + if (mSupplicantState != SupplicantState::IDLE) { + LOGD("Forcing Supplicant disconnect"); + if (mSupplicant->disconnect()) { + LOGW("Error disconnecting (%s)", strerror(errno)); + } + } + + LOGD("Stopping Supplicant driver"); + if (mSupplicant->stopDriver()) { + LOGE("Error stopping driver (%s)", strerror(errno)); + pthread_mutex_unlock(&mLock); + return -1; + } + } else { + LOGD("Resuming"); + + if (mSupplicant->startDriver()) { + LOGE("Error resuming driver (%s)", strerror(errno)); + pthread_mutex_unlock(&mLock); + return -1; + } + // XXX: set regulatory max channels + if (mScanOnly) + mSupplicant->triggerScan(); + else + mSupplicant->reconnect(); + + mHandlers->onControllerResumed(this); + } + + mSuspended = suspend; + pthread_mutex_unlock(&mLock); + LOGD("Suspend / Resume completed"); + return 0; +} + void WifiController::sendStatusBroadcast(const char *msg) { NetworkManager::Instance()-> getBroadcaster()-> - sendBroadcast(ErrorCode::UnsolicitedInformational, msg, false); + sendBroadcast(ResponseCode::UnsolicitedInformational, msg, false); } int WifiController::disable() { - mPropMngr->unregisterProperty("wifi.scanmode"); - mPropMngr->unregisterProperty("wifi.supplicant.state"); - mPropMngr->unregisterProperty("wifi.scanmode"); + mPropMngr->detachProperty("wifi", mDynamicProperties.propSupplicantState); + mPropMngr->detachProperty("wifi", mDynamicProperties.propActiveScan); + mPropMngr->detachProperty("wifi", mDynamicProperties.propInterface); + mPropMngr->detachProperty("wifi", mDynamicProperties.propSearching); + mPropMngr->detachProperty("wifi", mDynamicProperties.propPacketFilter); + mPropMngr->detachProperty("wifi", mDynamicProperties.propBluetoothCoexScan); + mPropMngr->detachProperty("wifi", mDynamicProperties.propBluetoothCoexMode); + mPropMngr->detachProperty("wifi", mDynamicProperties.propCurrentNetwork); + mPropMngr->detachProperty("wifi", mDynamicProperties.propRssi); + mPropMngr->detachProperty("wifi", mDynamicProperties.propLinkSpeed); + mPropMngr->detachProperty("wifi", mDynamicProperties.propSuspended); + mPropMngr->detachProperty("wifi", mDynamicProperties.propNetCount); if (mSupplicant->isStarted()) { sendStatusBroadcast("Stopping WPA Supplicant"); @@ -178,35 +297,61 @@ int WifiController::loadFirmware() { return 0; } -int WifiController::setScanMode(uint32_t mode) { - int rc = 0; +int WifiController::triggerScan() { + pthread_mutex_lock(&mLock); + if (verifyNotSuspended()) { + pthread_mutex_unlock(&mLock); + return -1; + } - if (mCurrentScanMode == mode) - return 0; + switch (mSupplicantState) { + case SupplicantState::DISCONNECTED: + case SupplicantState::INACTIVE: + case SupplicantState::SCANNING: + case SupplicantState::IDLE: + break; + default: + // Switch to scan only mode + mSupplicant->setApScanMode(2); + break; + } - if (!(mode & SCAN_ENABLE_MASK)) { - if (mCurrentScanMode & SCAN_REPEAT_MASK) - mScanner->stop(); - } else if (mode & SCAN_REPEAT_MASK) - rc = mScanner->start(mode & SCAN_ACTIVE_MASK); - else - rc = mSupplicant->triggerScan(mode & SCAN_ACTIVE_MASK); + int rc = mSupplicant->triggerScan(); + pthread_mutex_unlock(&mLock); + return rc; +} - mCurrentScanMode = mode; +int WifiController::setActiveScan(bool active) { + pthread_mutex_lock(&mLock); + if (mActiveScan == active) { + pthread_mutex_unlock(&mLock); + return 0; + } + mActiveScan = active; + + int rc = mSupplicant->setScanMode(active); + pthread_mutex_unlock(&mLock); return rc; } WifiNetwork *WifiController::createNetwork() { + pthread_mutex_lock(&mLock); WifiNetwork *wn = mSupplicant->createNetwork(); + pthread_mutex_unlock(&mLock); return wn; } int WifiController::removeNetwork(int networkId) { + pthread_mutex_lock(&mLock); WifiNetwork *wn = mSupplicant->lookupNetwork(networkId); - if (!wn) + if (!wn) { + pthread_mutex_unlock(&mLock); return -1; - return mSupplicant->removeNetwork(wn); + } + int rc = mSupplicant->removeNetwork(wn); + pthread_mutex_unlock(&mLock); + return rc; } ScanResultCollection *WifiController::createScanResults() { @@ -225,45 +370,59 @@ WifiNetworkCollection *WifiController::createNetworkList() { return mSupplicant->createNetworkList(); } -int WifiController::set(const char *name, const char *value) { +int WifiController::setPacketFilter(bool enable) { int rc; - if (!strcmp(name, "wifi.enabled")) { - int en = atoi(value); + pthread_mutex_lock(&mLock); + if (enable) + rc = mSupplicant->enablePacketFilter(); + else + rc = mSupplicant->disablePacketFilter(); - if (en == mEnabled) - return 0; - rc = (en ? enable() : disable()); - if (!rc) - mEnabled = en; - } else if (!strcmp(name, "wifi.interface")) { - errno = EROFS; - return -1; - } else if (!strcmp(name, "wifi.scanmode")) - return setScanMode((uint32_t) strtoul(value, NULL, 0)); - else if (!strcmp(name, "wifi.supplicant.state")) { - errno = EROFS; - return -1; - } else - return Controller::set(name, value); + if (!rc) + mPacketFilter = enable; + pthread_mutex_unlock(&mLock); return rc; } -const char *WifiController::get(const char *name, char *buffer, size_t maxsize) { +int WifiController::setBluetoothCoexistenceScan(bool enable) { + int rc; + + pthread_mutex_lock(&mLock); - if (!strcmp(name, "wifi.enabled")) - snprintf(buffer, maxsize, "%d", mEnabled); - else if (!strcmp(name, "wifi.interface")) { - snprintf(buffer, maxsize, "%s", - (getBoundInterface() ? getBoundInterface() : "none")); - } else if (!strcmp(name, "wifi.scanmode")) - snprintf(buffer, maxsize, "0x%.8x", mCurrentScanMode); - else if (!strcmp(name, "wifi.supplicant.state")) - return SupplicantState::toString(mSupplicantState, buffer, maxsize); + if (enable) + rc = mSupplicant->enableBluetoothCoexistenceScan(); else - return Controller::get(name, buffer, maxsize); + rc = mSupplicant->disableBluetoothCoexistenceScan(); + + if (!rc) + mBluetoothCoexScan = enable; + pthread_mutex_unlock(&mLock); + return rc; +} - return buffer; +int WifiController::setScanOnly(bool scanOnly) { + pthread_mutex_lock(&mLock); + int rc = mSupplicant->setApScanMode((scanOnly ? 2 : 1)); + if (!rc) + mScanOnly = scanOnly; + if (!mSuspended) { + if (scanOnly) + mSupplicant->disconnect(); + else + mSupplicant->reconnect(); + } + pthread_mutex_unlock(&mLock); + return rc; +} + +int WifiController::setBluetoothCoexistenceMode(int mode) { + pthread_mutex_lock(&mLock); + int rc = mSupplicant->setBluetoothCoexistenceMode(mode); + if (!rc) + mBluetoothCoexMode = mode; + pthread_mutex_unlock(&mLock); + return rc; } void WifiController::onAssociatingEvent(SupplicantAssociatingEvent *evt) { @@ -296,6 +455,7 @@ void WifiController::onConnectedEvent(SupplicantConnectedEvent *evt) { return; } + mCurrentlyConnectedNetworkId = ss->getId(); if (!(wn = mSupplicant->lookupNetwork(ss->getId()))) { LOGW("Error looking up connected network id %d (%s)", ss->getId(), strerror(errno)); @@ -303,7 +463,7 @@ void WifiController::onConnectedEvent(SupplicantConnectedEvent *evt) { } delete ss; - mHandlers->onInterfaceConnected(this, wn->getIfaceCfg()); + mHandlers->onInterfaceConnected(this); } void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) { @@ -314,6 +474,10 @@ void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) { return; } + mNumScanResultsSinceLastStateChange++; + if (mNumScanResultsSinceLastStateChange >= 3) + mIsSupplicantSearching = false; + size_t len = 4096; if (mSupplicant->sendCommand("SCAN_RESULTS", reply, &len)) { @@ -346,10 +510,14 @@ void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) { while((linep = strtok_r(NULL, "\n", &linep_next))) mLatestScanResults->push_back(new ScanResult(linep)); + // Switch handling of scan results back to normal mode + mSupplicant->setApScanMode(1); + char *tmp; asprintf(&tmp, "Scan results ready (%d)", mLatestScanResults->size()); NetworkManager::Instance()->getBroadcaster()-> - sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false); + sendBroadcast(ResponseCode::ScanResultsReady, + tmp, false); free(tmp); pthread_mutex_unlock(&mLatestScanResultsLock); free(reply); @@ -359,11 +527,35 @@ void WifiController::onStateChangeEvent(SupplicantStateChangeEvent *evt) { char tmp[32]; char tmp2[32]; + if (evt->getState() == mSupplicantState) + return; + LOGD("onStateChangeEvent(%s -> %s)", SupplicantState::toString(mSupplicantState, tmp, sizeof(tmp)), SupplicantState::toString(evt->getState(), tmp2, sizeof(tmp2))); + if (evt->getState() != SupplicantState::SCANNING) { + mIsSupplicantSearching = true; + mNumScanResultsSinceLastStateChange = 0; + } + + char *tmp3; + asprintf(&tmp3, + "Supplicant state changed from %d (%s) -> %d (%s)", + mSupplicantState, tmp, evt->getState(), tmp2); + mSupplicantState = evt->getState(); + + if (mSupplicantState == SupplicantState::COMPLETED) { + mStatusPoller->start(); + } else if (mStatusPoller->isStarted()) { + mStatusPoller->stop(); + } + + NetworkManager::Instance()->getBroadcaster()-> + sendBroadcast(ResponseCode::SupplicantStateChange, + tmp3, false); + free(tmp3); } void WifiController::onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt) { @@ -371,7 +563,8 @@ void WifiController::onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent * } void WifiController::onDisconnectedEvent(SupplicantDisconnectedEvent *evt) { - mHandlers->onInterfaceDisconnected(this, getBoundInterface()); + mCurrentlyConnectedNetworkId = -1; + mHandlers->onInterfaceDisconnected(this); } #if 0 @@ -411,3 +604,216 @@ void WifiController::onDriverStateEvent(SupplicantEvent *evt) { LOGD("onDriverStateEvent(%s)", evt->getEvent()); } #endif + +void WifiController::onStatusPollInterval() { + pthread_mutex_lock(&mLock); + int rssi; + if (mSupplicant->getRssi(&rssi)) { + LOGE("Failed to get rssi (%s)", strerror(errno)); + pthread_mutex_unlock(&mLock); + return; + } + + if (abs(mLastRssi - rssi) > mRssiEventThreshold) { + char *tmp3; + asprintf(&tmp3, "RSSI changed from %d -> %d", + mLastRssi, rssi); + mLastRssi = rssi; + NetworkManager::Instance()->getBroadcaster()-> + sendBroadcast(ResponseCode::RssiChange, + tmp3, false); + free(tmp3); + } + + int linkspeed = mSupplicant->getLinkSpeed(); + if (linkspeed != mLastLinkSpeed) { + char *tmp3; + asprintf(&tmp3, "Link speed changed from %d -> %d", + mLastLinkSpeed, linkspeed); + mLastLinkSpeed = linkspeed; + NetworkManager::Instance()->getBroadcaster()-> + sendBroadcast(ResponseCode::LinkSpeedChange, + tmp3, false); + free(tmp3); + + } + pthread_mutex_unlock(&mLock); +} + +int WifiController::verifyNotSuspended() { + if (mSuspended) { + errno = ESHUTDOWN; + return -1; + } + return 0; +} + +/* + * Property inner classes + */ + +WifiController::WifiIntegerProperty::WifiIntegerProperty(WifiController *c, + const char *name, + bool ro, + int elements) : + IntegerProperty(name, ro, elements) { + mWc = c; +} + +WifiController::WifiStringProperty::WifiStringProperty(WifiController *c, + const char *name, + bool ro, int elements) : + StringProperty(name, ro, elements) { + mWc = c; +} + +WifiController::WifiEnabledProperty::WifiEnabledProperty(WifiController *c) : + WifiIntegerProperty(c, "Enabled", false, 1) { +} + +int WifiController::WifiEnabledProperty::get(int idx, int *buffer) { + *buffer = mWc->mEnabled; + return 0; +} +int WifiController::WifiEnabledProperty::set(int idx, int value) { + int rc = (value ? mWc->enable() : mWc->disable()); + if (!rc) + mWc->mEnabled = value; + return rc; +} + +WifiController::WifiScanOnlyProperty::WifiScanOnlyProperty(WifiController *c) : + WifiIntegerProperty(c, "ScanOnly", false, 1) { +} +int WifiController::WifiScanOnlyProperty::get(int idx, int *buffer) { + *buffer = mWc->mScanOnly; + return 0; +} +int WifiController::WifiScanOnlyProperty::set(int idx, int value) { + return mWc->setScanOnly(value == 1); +} + +WifiController::WifiAllowedChannelsProperty::WifiAllowedChannelsProperty(WifiController *c) : + WifiIntegerProperty(c, "AllowedChannels", false, 1) { +} +int WifiController::WifiAllowedChannelsProperty::get(int idx, int *buffer) { + *buffer = mWc->mNumAllowedChannels; + return 0; +} +int WifiController::WifiAllowedChannelsProperty::set(int idx, int value) { + // XXX: IMPL + errno = ENOSYS; + return -1; +} + +WifiController::WifiSupplicantStateProperty::WifiSupplicantStateProperty(WifiController *c) : + WifiStringProperty(c, "SupplicantState", true, 1) { +} +int WifiController::WifiSupplicantStateProperty::get(int idx, char *buffer, size_t max) { + if (!SupplicantState::toString(mWc->mSupplicantState, buffer, max)) + return -1; + return 0; +} + +WifiController::WifiActiveScanProperty::WifiActiveScanProperty(WifiController *c) : + WifiIntegerProperty(c, "ActiveScan", false, 1) { +} +int WifiController::WifiActiveScanProperty::get(int idx, int *buffer) { + *buffer = mWc->mActiveScan; + return 0; +} +int WifiController::WifiActiveScanProperty::set(int idx, int value) { + return mWc->setActiveScan(value); +} + +WifiController::WifiInterfaceProperty::WifiInterfaceProperty(WifiController *c) : + WifiStringProperty(c, "Interface", true, 1) { +} +int WifiController::WifiInterfaceProperty::get(int idx, char *buffer, size_t max) { + strncpy(buffer, (mWc->getBoundInterface() ? mWc->getBoundInterface() : "none"), max); + return 0; +} + +WifiController::WifiSearchingProperty::WifiSearchingProperty(WifiController *c) : + WifiIntegerProperty(c, "Searching", true, 1) { +} +int WifiController::WifiSearchingProperty::get(int idx, int *buffer) { + *buffer = mWc->mIsSupplicantSearching; + return 0; +} + +WifiController::WifiPacketFilterProperty::WifiPacketFilterProperty(WifiController *c) : + WifiIntegerProperty(c, "PacketFilter", false, 1) { +} +int WifiController::WifiPacketFilterProperty::get(int idx, int *buffer) { + *buffer = mWc->mPacketFilter; + return 0; +} +int WifiController::WifiPacketFilterProperty::set(int idx, int value) { + return mWc->setPacketFilter(value); +} + +WifiController::WifiBluetoothCoexScanProperty::WifiBluetoothCoexScanProperty(WifiController *c) : + WifiIntegerProperty(c, "BluetoothCoexScan", false, 1) { +} +int WifiController::WifiBluetoothCoexScanProperty::get(int idx, int *buffer) { + *buffer = mWc->mBluetoothCoexScan; + return 0; +} +int WifiController::WifiBluetoothCoexScanProperty::set(int idx, int value) { + return mWc->setBluetoothCoexistenceScan(value == 1); +} + +WifiController::WifiBluetoothCoexModeProperty::WifiBluetoothCoexModeProperty(WifiController *c) : + WifiIntegerProperty(c, "BluetoothCoexMode", false, 1) { +} +int WifiController::WifiBluetoothCoexModeProperty::get(int idx, int *buffer) { + *buffer = mWc->mBluetoothCoexMode; + return 0; +} +int WifiController::WifiBluetoothCoexModeProperty::set(int idx, int value) { + return mWc->setBluetoothCoexistenceMode(value); +} + +WifiController::WifiCurrentNetworkProperty::WifiCurrentNetworkProperty(WifiController *c) : + WifiIntegerProperty(c, "CurrentlyConnectedNetworkId", true, 1) { +} +int WifiController::WifiCurrentNetworkProperty::get(int idx, int *buffer) { + *buffer = mWc->mCurrentlyConnectedNetworkId; + return 0; +} + +WifiController::WifiSuspendedProperty::WifiSuspendedProperty(WifiController *c) : + WifiIntegerProperty(c, "Suspended", false, 1) { +} +int WifiController::WifiSuspendedProperty::get(int idx, int *buffer) { + *buffer = mWc->getSuspended(); + return 0; +} +int WifiController::WifiSuspendedProperty::set(int idx, int value) { + return mWc->setSuspend(value == 1); +} + +WifiController::WifiNetCountProperty::WifiNetCountProperty(WifiController *c) : + WifiIntegerProperty(c, "NetCount", true, 1) { +} +int WifiController::WifiNetCountProperty::get(int idx, int *buffer) { + pthread_mutex_lock(&mWc->mLock); + *buffer = mWc->mSupplicant->getNetworkCount(); + pthread_mutex_unlock(&mWc->mLock); + return 0; +} + +WifiController::WifiTriggerScanProperty::WifiTriggerScanProperty(WifiController *c) : + WifiIntegerProperty(c, "TriggerScan", false, 1) { +} +int WifiController::WifiTriggerScanProperty::get(int idx, int *buffer) { + // XXX: Need action type + *buffer = 0; + return 0; +} + +int WifiController::WifiTriggerScanProperty::set(int idx, int value) { + return mWc->triggerScan(); +} + diff --git a/nexus/WifiController.h b/nexus/WifiController.h index c61d97a5a0d..b1524f66db0 100644 --- a/nexus/WifiController.h +++ b/nexus/WifiController.h @@ -23,41 +23,207 @@ #include "ScanResult.h" #include "WifiNetwork.h" #include "ISupplicantEventHandler.h" +#include "IWifiStatusPollerHandler.h" class NetInterface; class Supplicant; -class WifiScanner; class SupplicantAssociatingEvent; class SupplicantAssociatedEvent; class SupplicantConnectedEvent; class SupplicantScanResultsEvent; class SupplicantStateChangeEvent; class SupplicantDisconnectedEvent; +class WifiStatusPoller; -class WifiController : public Controller, public ISupplicantEventHandler { -public: - static const uint32_t SCAN_ENABLE_MASK = 0x01; - static const uint32_t SCAN_ACTIVE_MASK = 0x02; - static const uint32_t SCAN_REPEAT_MASK = 0x04; +class WifiController : public Controller, + public ISupplicantEventHandler, + public IWifiStatusPollerHandler { - static const uint32_t SCANMODE_NONE = 0; - static const uint32_t SCANMODE_PASSIVE_ONESHOT = SCAN_ENABLE_MASK; - static const uint32_t SCANMODE_PASSIVE_CONTINUOUS = SCAN_ENABLE_MASK | SCAN_REPEAT_MASK; - static const uint32_t SCANMODE_ACTIVE_ONESHOT = SCAN_ENABLE_MASK | SCAN_ACTIVE_MASK; - static const uint32_t SCANMODE_ACTIVE_CONTINUOUS = SCAN_ENABLE_MASK | SCAN_ACTIVE_MASK | SCAN_REPEAT_MASK; + class WifiIntegerProperty : public IntegerProperty { + protected: + WifiController *mWc; + public: + WifiIntegerProperty(WifiController *c, const char *name, bool ro, + int elements); + virtual ~WifiIntegerProperty() {} + virtual int set(int idx, int value) = 0; + virtual int get(int idx, int *buffer) = 0; + }; + friend class WifiController::WifiIntegerProperty; + + class WifiStringProperty : public StringProperty { + protected: + WifiController *mWc; + public: + WifiStringProperty(WifiController *c, const char *name, bool ro, + int elements); + virtual ~WifiStringProperty() {} + virtual int set(int idx, const char *value) = 0; + virtual int get(int idx, char *buffer, size_t max) = 0; + }; + friend class WifiController::WifiStringProperty; + + class WifiEnabledProperty : public WifiIntegerProperty { + public: + WifiEnabledProperty(WifiController *c); + virtual ~WifiEnabledProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiScanOnlyProperty : public WifiIntegerProperty { + public: + WifiScanOnlyProperty(WifiController *c); + virtual ~WifiScanOnlyProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiAllowedChannelsProperty : public WifiIntegerProperty { + public: + WifiAllowedChannelsProperty(WifiController *c); + virtual ~WifiAllowedChannelsProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiActiveScanProperty : public WifiIntegerProperty { + public: + WifiActiveScanProperty(WifiController *c); + virtual ~WifiActiveScanProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiSearchingProperty : public WifiIntegerProperty { + public: + WifiSearchingProperty(WifiController *c); + virtual ~WifiSearchingProperty() {} + int set(int idx, int value) { return -1; } + int get(int idx, int *buffer); + }; + + class WifiPacketFilterProperty : public WifiIntegerProperty { + public: + WifiPacketFilterProperty(WifiController *c); + virtual ~WifiPacketFilterProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiBluetoothCoexScanProperty : public WifiIntegerProperty { + public: + WifiBluetoothCoexScanProperty(WifiController *c); + virtual ~WifiBluetoothCoexScanProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiBluetoothCoexModeProperty : public WifiIntegerProperty { + public: + WifiBluetoothCoexModeProperty(WifiController *c); + virtual ~WifiBluetoothCoexModeProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiCurrentNetworkProperty : public WifiIntegerProperty { + public: + WifiCurrentNetworkProperty(WifiController *c); + virtual ~WifiCurrentNetworkProperty() {} + int set(int idx, int value) { return -1; } + int get(int idx, int *buffer); + }; + + class WifiSuspendedProperty : public WifiIntegerProperty { + public: + WifiSuspendedProperty(WifiController *c); + virtual ~WifiSuspendedProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiNetCountProperty : public WifiIntegerProperty { + public: + WifiNetCountProperty(WifiController *c); + virtual ~WifiNetCountProperty() {} + int set(int idx, int value) { return -1; } + int get(int idx, int *buffer); + }; + + class WifiTriggerScanProperty : public WifiIntegerProperty { + public: + WifiTriggerScanProperty(WifiController *c); + virtual ~WifiTriggerScanProperty() {} + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiSupplicantStateProperty : public WifiStringProperty { + public: + WifiSupplicantStateProperty(WifiController *c); + virtual ~WifiSupplicantStateProperty() {} + int set(int idx, const char *value) { return -1; } + int get(int idx, char *buffer, size_t max); + }; + + class WifiInterfaceProperty : public WifiStringProperty { + public: + WifiInterfaceProperty(WifiController *c); + virtual ~WifiInterfaceProperty() {} + int set(int idx, const char *value) { return -1; } + int get(int idx, char *buffer, size_t max); + }; -private: Supplicant *mSupplicant; char mModulePath[255]; char mModuleName[64]; char mModuleArgs[255]; - uint32_t mCurrentScanMode; - WifiScanner *mScanner; int mSupplicantState; + bool mActiveScan; + bool mScanOnly; + bool mPacketFilter; + bool mBluetoothCoexScan; + int mBluetoothCoexMode; + int mCurrentlyConnectedNetworkId; + bool mSuspended; + int mLastRssi; + int mRssiEventThreshold; + int mLastLinkSpeed; + int mNumAllowedChannels; ScanResultCollection *mLatestScanResults; pthread_mutex_t mLatestScanResultsLock; + pthread_mutex_t mLock; + WifiStatusPoller *mStatusPoller; + + struct { + WifiEnabledProperty *propEnabled; + WifiScanOnlyProperty *propScanOnly; + WifiAllowedChannelsProperty *propAllowedChannels; + IntegerPropertyHelper *propRssiEventThreshold; + } mStaticProperties; + + struct { + WifiActiveScanProperty *propActiveScan; + WifiSearchingProperty *propSearching; + WifiPacketFilterProperty *propPacketFilter; + WifiBluetoothCoexScanProperty *propBluetoothCoexScan; + WifiBluetoothCoexModeProperty *propBluetoothCoexMode; + WifiCurrentNetworkProperty *propCurrentNetwork; + IntegerPropertyHelper *propRssi; + IntegerPropertyHelper *propLinkSpeed; + WifiSuspendedProperty *propSuspended; + WifiNetCountProperty *propNetCount; + WifiSupplicantStateProperty *propSupplicantState; + WifiInterfaceProperty *propInterface; + WifiTriggerScanProperty *propTriggerScan; + } mDynamicProperties; + + // True if supplicant is currently searching for a network + bool mIsSupplicantSearching; + int mNumScanResultsSinceLastStateChange; bool mEnabled; @@ -72,9 +238,6 @@ class WifiController : public Controller, public ISupplicantEventHandler { int removeNetwork(int networkId); WifiNetworkCollection *createNetworkList(); - virtual int set(const char *name, const char *value); - virtual const char *get(const char *name, char *buffer, size_t maxlen); - ScanResultCollection *createScanResults(); char *getModulePath() { return mModulePath; } @@ -94,18 +257,25 @@ class WifiController : public Controller, public ISupplicantEventHandler { private: void sendStatusBroadcast(const char *msg); - int setScanMode(uint32_t mode); + int setActiveScan(bool active); + int triggerScan(); int enable(); int disable(); + int setSuspend(bool suspend); + bool getSuspended(); + int setBluetoothCoexistenceScan(bool enable); + int setBluetoothCoexistenceMode(int mode); + int setPacketFilter(bool enable); + int setScanOnly(bool scanOnly); // ISupplicantEventHandler methods - virtual void onAssociatingEvent(SupplicantAssociatingEvent *evt); - virtual void onAssociatedEvent(SupplicantAssociatedEvent *evt); - virtual void onConnectedEvent(SupplicantConnectedEvent *evt); - virtual void onScanResultsEvent(SupplicantScanResultsEvent *evt); - virtual void onStateChangeEvent(SupplicantStateChangeEvent *evt); - virtual void onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt); - virtual void onDisconnectedEvent(SupplicantDisconnectedEvent *evt); + void onAssociatingEvent(SupplicantAssociatingEvent *evt); + void onAssociatedEvent(SupplicantAssociatedEvent *evt); + void onConnectedEvent(SupplicantConnectedEvent *evt); + void onScanResultsEvent(SupplicantScanResultsEvent *evt); + void onStateChangeEvent(SupplicantStateChangeEvent *evt); + void onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt); + void onDisconnectedEvent(SupplicantDisconnectedEvent *evt); #if 0 virtual void onTerminatingEvent(SupplicantEvent *evt); virtual void onPasswordChangedEvent(SupplicantEvent *evt); @@ -118,6 +288,9 @@ class WifiController : public Controller, public ISupplicantEventHandler { virtual void onDriverStateEvent(SupplicantEvent *evt); #endif + void onStatusPollInterval(); + + int verifyNotSuspended(); }; #endif diff --git a/nexus/WifiNetwork.cpp b/nexus/WifiNetwork.cpp index 7059bd04b54..6a0f6840b38 100644 --- a/nexus/WifiNetwork.cpp +++ b/nexus/WifiNetwork.cpp @@ -26,17 +26,7 @@ #include "WifiNetwork.h" #include "Supplicant.h" #include "WifiController.h" -#include "InterfaceConfig.h" - -const char *WifiNetwork::PropertyNames[] = { "ssid", "bssid", "psk", "wepkey.1", - "wepkey.2", "wepkey.3", "wepkey.4", - "defkeyidx", "pri", "hiddenssid", - "AllowedKeyManagement", - "AllowedProtocols", - "AllowedAuthAlgorithms", - "AllowedPairwiseCiphers", - "AllowedGroupCiphers", - "enabled", '\0' }; + WifiNetwork::WifiNetwork() { // This is private to restrict copy constructors } @@ -76,11 +66,11 @@ WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, const char *data) mDefaultKeyIndex = -1; mPriority = -1; mHiddenSsid = NULL; - mAllowedKeyManagement = KeyManagementMask::UNKNOWN; - mAllowedProtocols = 0; - mAllowedAuthAlgorithms = 0; - mAllowedPairwiseCiphers = 0; - mAllowedGroupCiphers = 0; + mKeyManagement = KeyManagementMask::UNKNOWN; + mProtocols = 0; + mAuthAlgorithms = 0; + mPairwiseCiphers = 0; + mGroupCiphers = 0; mEnabled = true; if (flags && flags[0] != '\0') { @@ -90,11 +80,8 @@ WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, const char *data) LOGW("Unsupported flags '%s'", flags); } - char *tmp2; - asprintf(&tmp2, "wifi.net.%d", mNetid); - mIfaceCfg = new InterfaceConfig(tmp2); - free(tmp2); free(tmp); + createProperties(); } WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, int networkId) { @@ -108,17 +95,13 @@ WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, int networkId) { mDefaultKeyIndex = -1; mPriority = -1; mHiddenSsid = NULL; - mAllowedKeyManagement = 0; - mAllowedProtocols = 0; - mAllowedAuthAlgorithms = 0; - mAllowedPairwiseCiphers = 0; - mAllowedGroupCiphers = 0; + mKeyManagement = 0; + mProtocols = 0; + mAuthAlgorithms = 0; + mPairwiseCiphers = 0; + mGroupCiphers = 0; mEnabled = false; - - char *tmp2; - asprintf(&tmp2, "wifi.net.%d", mNetid); - mIfaceCfg = new InterfaceConfig(tmp2); - free(tmp2); + createProperties(); } WifiNetwork *WifiNetwork::clone() { @@ -140,15 +123,35 @@ WifiNetwork *WifiNetwork::clone() { r->mPriority = mPriority; if (mHiddenSsid) r->mHiddenSsid = strdup(mHiddenSsid); - r->mAllowedKeyManagement = mAllowedKeyManagement; - r->mAllowedProtocols = mAllowedProtocols; - r->mAllowedAuthAlgorithms = mAllowedAuthAlgorithms; - r->mAllowedPairwiseCiphers = mAllowedPairwiseCiphers; - r->mAllowedGroupCiphers = mAllowedGroupCiphers; + r->mKeyManagement = mKeyManagement; + r->mProtocols = mProtocols; + r->mAuthAlgorithms = mAuthAlgorithms; + r->mPairwiseCiphers = mPairwiseCiphers; + r->mGroupCiphers = mGroupCiphers; return r; } +void WifiNetwork::createProperties() { + asprintf(&mPropNamespace, "wifi.net.%d", mNetid); + + mStaticProperties.propEnabled = new WifiNetworkEnabledProperty(this); + mStaticProperties.propSsid = new WifiNetworkSsidProperty(this); + mStaticProperties.propBssid = new WifiNetworkBssidProperty(this); + mStaticProperties.propPsk = new WifiNetworkPskProperty(this); + mStaticProperties.propWepKey = new WifiNetworkWepKeyProperty(this); + mStaticProperties.propDefKeyIdx = new WifiNetworkDefaultKeyIndexProperty(this); + mStaticProperties.propPriority = new WifiNetworkPriorityProperty(this); + mStaticProperties.propKeyManagement = new WifiNetworkKeyManagementProperty(this); + mStaticProperties.propProtocols = new WifiNetworkProtocolsProperty(this); + mStaticProperties.propAuthAlgorithms = new WifiNetworkAuthAlgorithmsProperty(this); + mStaticProperties.propPairwiseCiphers = new WifiNetworkPairwiseCiphersProperty(this); + mStaticProperties.propGroupCiphers = new WifiNetworkGroupCiphersProperty(this); + mStaticProperties.propHiddenSsid = new WifiNetworkHiddenSsidProperty(this); +} + WifiNetwork::~WifiNetwork() { + if (mPropNamespace) + free(mPropNamespace); if (mSsid) free(mSsid); if (mBssid) @@ -162,13 +165,26 @@ WifiNetwork::~WifiNetwork() { if (mHiddenSsid) free(mHiddenSsid); - if (mIfaceCfg) - delete(mIfaceCfg); + + delete mStaticProperties.propEnabled; + delete mStaticProperties.propSsid; + delete mStaticProperties.propBssid; + delete mStaticProperties.propPsk; + delete mStaticProperties.propWepKey; + delete mStaticProperties.propDefKeyIdx; + delete mStaticProperties.propPriority; + delete mStaticProperties.propKeyManagement; + delete mStaticProperties.propProtocols; + delete mStaticProperties.propAuthAlgorithms; + delete mStaticProperties.propPairwiseCiphers; + delete mStaticProperties.propGroupCiphers; + delete mStaticProperties.propHiddenSsid; } int WifiNetwork::refresh() { char buffer[255]; size_t len; + uint32_t mask; len = sizeof(buffer); if (mSuppl->getNetworkVar(mNetid, "psk", buffer, len)) @@ -198,46 +214,47 @@ int WifiNetwork::refresh() { len = sizeof(buffer); if (mSuppl->getNetworkVar(mNetid, "key_mgmt", buffer, len)) { - if (!strcmp(buffer, "NONE")) - setAllowedKeyManagement(KeyManagementMask::NONE); - else if (index(buffer, ' ')) { - char *next = buffer; - char *token; - uint32_t mask = 0; - - while((token = strsep(&next, " "))) { - if (!strcmp(token, "WPA-PSK")) - mask |= KeyManagementMask::WPA_PSK; - else if (!strcmp(token, "WPA-EAP")) - mask |= KeyManagementMask::WPA_EAP; - else if (!strcmp(token, "IEE8021X")) - mask |= KeyManagementMask::IEEE8021X; - else - LOGW("Unsupported key management scheme '%s'" , token); - } - setAllowedKeyManagement(mask); - } else - LOGE("Unsupported key management '%s'", buffer); + if (WifiNetwork::parseKeyManagementMask(buffer, &mask)) { + LOGE("Error parsing key_mgmt (%s)", strerror(errno)); + } else { + mKeyManagement = mask; + } } len = sizeof(buffer); if (mSuppl->getNetworkVar(mNetid, "proto", buffer, len)) { - // TODO + if (WifiNetwork::parseProtocolsMask(buffer, &mask)) { + LOGE("Error parsing proto (%s)", strerror(errno)); + } else { + mProtocols = mask; + } } len = sizeof(buffer); if (mSuppl->getNetworkVar(mNetid, "auth_alg", buffer, len)) { - // TODO + if (WifiNetwork::parseAuthAlgorithmsMask(buffer, &mask)) { + LOGE("Error parsing auth_alg (%s)", strerror(errno)); + } else { + mAuthAlgorithms = mask; + } } len = sizeof(buffer); if (mSuppl->getNetworkVar(mNetid, "pairwise", buffer, len)) { - // TODO + if (WifiNetwork::parsePairwiseCiphersMask(buffer, &mask)) { + LOGE("Error parsing pairwise (%s)", strerror(errno)); + } else { + mPairwiseCiphers = mask; + } } len = sizeof(buffer); if (mSuppl->getNetworkVar(mNetid, "group", buffer, len)) { - // TODO + if (WifiNetwork::parseGroupCiphersMask(buffer, &mask)) { + LOGE("Error parsing group (%s)", strerror(errno)); + } else { + mGroupCiphers = mask; + } } return 0; @@ -246,179 +263,10 @@ int WifiNetwork::refresh() { return -1; } -int WifiNetwork::set(const char *name, const char *value) { - char *n_tmp = strdup(name + strlen("wifi.net.")); - char *n_next = n_tmp; - char *n_local; - char *n_rest; - int rc = 0; - - if (!strsep(&n_next, ".")) // skip net id - goto out_inval; - - if (!(n_local = strsep(&n_next, "."))) - goto out_inval; - - n_rest = n_next; - -// LOGD("set(): var '%s'(%s / %s) = %s", name, n_local, n_rest, value); - if (!strcasecmp(n_local, "enabled")) - rc = setEnabled(atoi(value)); - else if (!strcmp(n_local, "ssid")) - rc = setSsid(value); - else if (!strcasecmp(n_local, "bssid")) - rc = setBssid(value); - else if (!strcasecmp(n_local, "psk")) - rc = setPsk(value); - else if (!strcasecmp(n_local, "wepkey")) - rc = setWepKey(atoi(n_rest) -1, value); - else if (!strcasecmp(n_local, "defkeyidx")) - rc = setDefaultKeyIndex(atoi(value)); - else if (!strcasecmp(n_local, "pri")) - rc = setPriority(atoi(value)); - else if (!strcasecmp(n_local, "hiddenssid")) - rc = setHiddenSsid(value); - else if (!strcasecmp(n_local, "AllowedKeyManagement")) { - uint32_t mask = 0; - bool none = false; - char *v_tmp = strdup(value); - char *v_next = v_tmp; - char *v_token; - - while((v_token = strsep(&v_next, " "))) { - if (!strcasecmp(v_token, "NONE")) { - mask = KeyManagementMask::NONE; - none = true; - } else if (!none) { - if (!strcasecmp(v_token, "WPA_PSK")) - mask |= KeyManagementMask::WPA_PSK; - else if (!strcasecmp(v_token, "WPA_EAP")) - mask |= KeyManagementMask::WPA_EAP; - else if (!strcasecmp(v_token, "IEEE8021X")) - mask |= KeyManagementMask::IEEE8021X; - else { - errno = EINVAL; - rc = -1; - free(v_tmp); - goto out; - } - } else { - errno = EINVAL; - rc = -1; - free(v_tmp); - goto out; - } - } - free(v_tmp); - } else if (!strcasecmp(n_local, "AllowedProtocols")) { - // TODO - } else if (!strcasecmp(n_local, "AllowedPairwiseCiphers")) { - // TODO - } else if (!strcasecmp(n_local, "AllowedAuthAlgorithms")) { - // TODO - } else if (!strcasecmp(n_local, "AllowedGroupCiphers")) { - // TODO - } else { - errno = ENOENT; - free(n_tmp); - return -1; - } - -out: - free(n_tmp); - return rc; - -out_inval: - errno = EINVAL; - free(n_tmp); - return -1; -} - -const char *WifiNetwork::get(const char *name, char *buffer, size_t maxsize) { - char *n_tmp = strdup(name + strlen("wifi.net.")); - char *n_next = n_tmp; - char *n_local; - char fc[64]; - char rc[128]; - - if (!strsep(&n_next, ".")) // skip net id - goto out_inval; - - if (!(n_local = strsep(&n_next, "."))) - goto out_inval; - - - strncpy(fc, n_local, sizeof(fc)); - rc[0] = '\0'; - if (n_next) - strncpy(rc, n_next, sizeof(rc)); - - free(n_tmp); - - if (!strcasecmp(fc, "enabled")) - snprintf(buffer, maxsize, "%d", getEnabled()); - else if (!strcasecmp(fc, "ssid")) { - strncpy(buffer, - getSsid() ? getSsid() : "none", - maxsize); - } else if (!strcasecmp(fc, "bssid")) { - strncpy(buffer, - getBssid() ? getBssid() : "none", - maxsize); - } else if (!strcasecmp(fc, "psk")) { - strncpy(buffer, - getPsk() ? getPsk() : "none", - maxsize); - } else if (!strcasecmp(fc, "wepkey")) { - strncpy(buffer, - getWepKey(atoi(rc)-1) ? getWepKey(atoi(rc)-1) : "none", - maxsize); - } else if (!strcasecmp(fc, "defkeyidx")) - snprintf(buffer, maxsize, "%d", getDefaultKeyIndex()); - else if (!strcasecmp(fc, "pri")) - snprintf(buffer, maxsize, "%d", getPriority()); - else if (!strcasecmp(fc, "AllowedKeyManagement")) { - if (getAllowedKeyManagement() == KeyManagementMask::NONE) - strncpy(buffer, "NONE", maxsize); - else { - char tmp[80] = { '\0' }; - - if (getAllowedKeyManagement() & KeyManagementMask::WPA_PSK) - strcat(tmp, "WPA_PSK "); - if (getAllowedKeyManagement() & KeyManagementMask::WPA_EAP) - strcat(tmp, "WPA_EAP "); - if (getAllowedKeyManagement() & KeyManagementMask::IEEE8021X) - strcat(tmp, "IEEE8021X"); - if (tmp[0] == '\0') { - strncpy(buffer, "(internal error)", maxsize); - errno = ENOENT; - return NULL; - } - if (tmp[strlen(tmp)] == ' ') - tmp[strlen(tmp)] = '\0'; - - strncpy(buffer, tmp, maxsize); - } - } else if (!strcasecmp(fc, "hiddenssid")) { - strncpy(buffer, - getHiddenSsid() ? getHiddenSsid() : "none", - maxsize); - } else { - strncpy(buffer, "(internal error)", maxsize); - errno = ENOENT; - return NULL; - } - - return buffer; - -out_inval: - errno = EINVAL; - free(n_tmp); - return NULL; -} - int WifiNetwork::setSsid(const char *ssid) { - if (mSuppl->setNetworkVar(mNetid, "ssid", ssid)) + char tmp[255]; + snprintf(tmp, sizeof(tmp), "\"%s\"", ssid); + if (mSuppl->setNetworkVar(mNetid, "ssid", tmp)) return -1; if (mSsid) free(mSsid); @@ -436,7 +284,9 @@ int WifiNetwork::setBssid(const char *bssid) { } int WifiNetwork::setPsk(const char *psk) { - if (mSuppl->setNetworkVar(mNetid, "psk", psk)) + char tmp[255]; + snprintf(tmp, sizeof(tmp), "\"%s\"", psk); + if (mSuppl->setNetworkVar(mNetid, "psk", tmp)) return -1; if (mPsk) @@ -491,28 +341,34 @@ int WifiNetwork::setHiddenSsid(const char *ssid) { return 0; } -int WifiNetwork::setAllowedKeyManagement(uint32_t mask) { - char accum[255]; +int WifiNetwork::setKeyManagement(uint32_t mask) { + char accum[64] = {'\0'}; if (mask == KeyManagementMask::NONE) strcpy(accum, "NONE"); else { - if (mask & KeyManagementMask::WPA_PSK) - strcat(accum, "WPA_PSK "); - if (mask & KeyManagementMask::WPA_EAP) - strcat(accum, "WPA_EAP "); - if (mask & KeyManagementMask::IEEE8021X) - strcat(accum, "IEEE8021X "); + if (mask & KeyManagementMask::WPA_PSK) + strcat(accum, "WPA-PSK"); + if (mask & KeyManagementMask::WPA_EAP) { + if (accum[0] != '\0') + strcat(accum, " "); + strcat(accum, "WPA-EAP"); + } + if (mask & KeyManagementMask::IEEE8021X) { + if (accum[0] != '\0') + strcat(accum, " "); + strcat(accum, "IEEE8021X"); + } } if (mSuppl->setNetworkVar(mNetid, "key_mgmt", accum)) return -1; - mAllowedKeyManagement = mask; + mKeyManagement = mask; return 0; } -int WifiNetwork::setAllowedProtocols(uint32_t mask) { - char accum[255]; +int WifiNetwork::setProtocols(uint32_t mask) { + char accum[64]; accum[0] = '\0'; @@ -524,15 +380,18 @@ int WifiNetwork::setAllowedProtocols(uint32_t mask) { if (mSuppl->setNetworkVar(mNetid, "proto", accum)) return -1; - mAllowedProtocols = mask; + mProtocols = mask; return 0; } -int WifiNetwork::setAllowedAuthAlgorithms(uint32_t mask) { - char accum[255]; +int WifiNetwork::setAuthAlgorithms(uint32_t mask) { + char accum[64]; accum[0] = '\0'; + if (mask == 0) + strcpy(accum, ""); + if (mask & AuthenticationAlgorithmMask::OPEN) strcpy(accum, "OPEN "); @@ -545,12 +404,14 @@ int WifiNetwork::setAllowedAuthAlgorithms(uint32_t mask) { if (mSuppl->setNetworkVar(mNetid, "auth_alg", accum)) return -1; - mAllowedAuthAlgorithms = mask; + mAuthAlgorithms = mask; return 0; } -int WifiNetwork::setAllowedPairwiseCiphers(uint32_t mask) { - char accum[255]; +int WifiNetwork::setPairwiseCiphers(uint32_t mask) { + char accum[64]; + + accum[0] = '\0'; if (mask == PairwiseCiphersMask::NONE) strcpy(accum, "NONE"); @@ -564,12 +425,14 @@ int WifiNetwork::setAllowedPairwiseCiphers(uint32_t mask) { if (mSuppl->setNetworkVar(mNetid, "pairwise", accum)) return -1; - mAllowedPairwiseCiphers = mask; + mPairwiseCiphers = mask; return 0; } -int WifiNetwork::setAllowedGroupCiphers(uint32_t mask) { - char accum[255]; +int WifiNetwork::setGroupCiphers(uint32_t mask) { + char accum[64]; + + accum[0] = '\0'; if (mask & GroupCiphersMask::WEP40) strcat(accum, "WEP40 "); @@ -582,7 +445,7 @@ int WifiNetwork::setAllowedGroupCiphers(uint32_t mask) { if (mSuppl->setNetworkVar(mNetid, "group", accum)) return -1; - mAllowedGroupCiphers = mask; + mGroupCiphers = mask; return 0; } @@ -594,7 +457,7 @@ int WifiNetwork::setEnabled(bool enabled) { errno = EAGAIN; return -1; } - if (getAllowedKeyManagement() == KeyManagementMask::UNKNOWN) { + if (getKeyManagement() == KeyManagementMask::UNKNOWN) { LOGE("Cannot enable network when KeyManagement is not set"); errno = EAGAIN; return -1; @@ -608,29 +471,500 @@ int WifiNetwork::setEnabled(bool enabled) { return 0; } -int WifiNetwork::registerProperties() { - for (const char **p = WifiNetwork::PropertyNames; *p != '\0'; p++) { - char *tmp; - asprintf(&tmp, "wifi.net.%d.%s", mNetid, *p); +int WifiNetwork::attachProperties(PropertyManager *pm, const char *nsName) { + pm->attachProperty(nsName, mStaticProperties.propSsid); + pm->attachProperty(nsName, mStaticProperties.propBssid); + pm->attachProperty(nsName, mStaticProperties.propPsk); + pm->attachProperty(nsName, mStaticProperties.propWepKey); + pm->attachProperty(nsName, mStaticProperties.propDefKeyIdx); + pm->attachProperty(nsName, mStaticProperties.propPriority); + pm->attachProperty(nsName, mStaticProperties.propKeyManagement); + pm->attachProperty(nsName, mStaticProperties.propProtocols); + pm->attachProperty(nsName, mStaticProperties.propAuthAlgorithms); + pm->attachProperty(nsName, mStaticProperties.propPairwiseCiphers); + pm->attachProperty(nsName, mStaticProperties.propGroupCiphers); + pm->attachProperty(nsName, mStaticProperties.propHiddenSsid); + pm->attachProperty(nsName, mStaticProperties.propEnabled); + return 0; +} + +int WifiNetwork::detachProperties(PropertyManager *pm, const char *nsName) { + pm->detachProperty(nsName, mStaticProperties.propEnabled); + pm->detachProperty(nsName, mStaticProperties.propSsid); + pm->detachProperty(nsName, mStaticProperties.propBssid); + pm->detachProperty(nsName, mStaticProperties.propPsk); + pm->detachProperty(nsName, mStaticProperties.propWepKey); + pm->detachProperty(nsName, mStaticProperties.propDefKeyIdx); + pm->detachProperty(nsName, mStaticProperties.propPriority); + pm->detachProperty(nsName, mStaticProperties.propKeyManagement); + pm->detachProperty(nsName, mStaticProperties.propProtocols); + pm->detachProperty(nsName, mStaticProperties.propAuthAlgorithms); + pm->detachProperty(nsName, mStaticProperties.propPairwiseCiphers); + pm->detachProperty(nsName, mStaticProperties.propGroupCiphers); + pm->detachProperty(nsName, mStaticProperties.propHiddenSsid); + return 0; +} + +int WifiNetwork::parseKeyManagementMask(const char *buffer, uint32_t *mask) { + bool none = false; + char *v_tmp = strdup(buffer); + char *v_next = v_tmp; + char *v_token; + +// LOGD("parseKeyManagementMask(%s)", buffer); + *mask = 0; + + while((v_token = strsep(&v_next, " "))) { + if (!strcasecmp(v_token, "NONE")) { + *mask = KeyManagementMask::NONE; + none = true; + } else if (!none) { + if (!strcasecmp(v_token, "WPA-PSK")) + *mask |= KeyManagementMask::WPA_PSK; + else if (!strcasecmp(v_token, "WPA-EAP")) + *mask |= KeyManagementMask::WPA_EAP; + else if (!strcasecmp(v_token, "IEEE8021X")) + *mask |= KeyManagementMask::IEEE8021X; + else { + LOGW("Invalid KeyManagementMask value '%s'", v_token); + errno = EINVAL; + free(v_tmp); + return -1; + } + } else { + LOGW("KeyManagementMask value '%s' when NONE", v_token); + errno = EINVAL; + free(v_tmp); + return -1; + } + } + free(v_tmp); + return 0; +} + +int WifiNetwork::parseProtocolsMask(const char *buffer, uint32_t *mask) { + bool none = false; + char *v_tmp = strdup(buffer); + char *v_next = v_tmp; + char *v_token; + +// LOGD("parseProtocolsMask(%s)", buffer); + *mask = 0; + while((v_token = strsep(&v_next, " "))) { + if (!strcasecmp(v_token, "WPA")) + *mask |= SecurityProtocolMask::WPA; + else if (!strcasecmp(v_token, "RSN")) + *mask |= SecurityProtocolMask::RSN; + else { + LOGW("Invalid ProtocolsMask value '%s'", v_token); + errno = EINVAL; + free(v_tmp); + return -1; + } + } + + free(v_tmp); + return 0; +} - if (NetworkManager::Instance()->getPropMngr()->registerProperty(tmp, - this)) { - free(tmp); +int WifiNetwork::parseAuthAlgorithmsMask(const char *buffer, uint32_t *mask) { + bool none = false; + char *v_tmp = strdup(buffer); + char *v_next = v_tmp; + char *v_token; + +// LOGD("parseAuthAlgorithmsMask(%s)", buffer); + + *mask = 0; + if (buffer[0] == '\0') + return 0; + + while((v_token = strsep(&v_next, " "))) { + if (!strcasecmp(v_token, "OPEN")) + *mask |= AuthenticationAlgorithmMask::OPEN; + else if (!strcasecmp(v_token, "SHARED")) + *mask |= AuthenticationAlgorithmMask::SHARED; + else if (!strcasecmp(v_token, "LEAP")) + *mask |= AuthenticationAlgorithmMask::LEAP; + else { + LOGW("Invalid AuthAlgorithmsMask value '%s'", v_token); + errno = EINVAL; + free(v_tmp); return -1; } - free(tmp); } + free(v_tmp); return 0; } -int WifiNetwork::unregisterProperties() { - for (const char **p = WifiNetwork::PropertyNames; *p != '\0'; p++) { - char *tmp; - asprintf(&tmp, "wifi.net.%d.%s", mNetid, *p); +int WifiNetwork::parsePairwiseCiphersMask(const char *buffer, uint32_t *mask) { + bool none = false; + char *v_tmp = strdup(buffer); + char *v_next = v_tmp; + char *v_token; + +// LOGD("parsePairwiseCiphersMask(%s)", buffer); + + *mask = 0; + while((v_token = strsep(&v_next, " "))) { + if (!strcasecmp(v_token, "NONE")) { + *mask = PairwiseCiphersMask::NONE; + none = true; + } else if (!none) { + if (!strcasecmp(v_token, "TKIP")) + *mask |= PairwiseCiphersMask::TKIP; + else if (!strcasecmp(v_token, "CCMP")) + *mask |= PairwiseCiphersMask::CCMP; + else { + LOGW("PairwiseCiphersMask value '%s' when NONE", v_token); + errno = EINVAL; + free(v_tmp); + return -1; + } + } else { + LOGW("Invalid PairwiseCiphersMask value '%s'", v_token); + errno = EINVAL; + free(v_tmp); + return -1; + } + } + free(v_tmp); + return 0; +} - if (NetworkManager::Instance()->getPropMngr()->unregisterProperty(tmp)) - LOGW("Unable to remove property '%s' (%s)", tmp, strerror(errno)); - free(tmp); +int WifiNetwork::parseGroupCiphersMask(const char *buffer, uint32_t *mask) { + bool none = false; + char *v_tmp = strdup(buffer); + char *v_next = v_tmp; + char *v_token; + +// LOGD("parseGroupCiphersMask(%s)", buffer); + + *mask = 0; + while((v_token = strsep(&v_next, " "))) { + if (!strcasecmp(v_token, "WEP40")) + *mask |= GroupCiphersMask::WEP40; + else if (!strcasecmp(v_token, "WEP104")) + *mask |= GroupCiphersMask::WEP104; + else if (!strcasecmp(v_token, "TKIP")) + *mask |= GroupCiphersMask::TKIP; + else if (!strcasecmp(v_token, "CCMP")) + *mask |= GroupCiphersMask::CCMP; + else { + LOGW("Invalid GroupCiphersMask value '%s'", v_token); + errno = EINVAL; + free(v_tmp); + return -1; + } } + free(v_tmp); + return 0; +} + +WifiNetwork::WifiNetworkIntegerProperty::WifiNetworkIntegerProperty(WifiNetwork *wn, + const char *name, + bool ro, + int elements) : + IntegerProperty(name, ro, elements) { + mWn = wn; +} + +WifiNetwork::WifiNetworkStringProperty::WifiNetworkStringProperty(WifiNetwork *wn, + const char *name, + bool ro, int elements) : + StringProperty(name, ro, elements) { + mWn = wn; +} + +WifiNetwork::WifiNetworkEnabledProperty::WifiNetworkEnabledProperty(WifiNetwork *wn) : + WifiNetworkIntegerProperty(wn, "Enabled", false, 1) { +} + +int WifiNetwork::WifiNetworkEnabledProperty::get(int idx, int *buffer) { + *buffer = mWn->mEnabled; + return 0; +} +int WifiNetwork::WifiNetworkEnabledProperty::set(int idx, int value) { + return mWn->setEnabled(value == 1); +} + +WifiNetwork::WifiNetworkSsidProperty::WifiNetworkSsidProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "Ssid", false, 1) { +} + +int WifiNetwork::WifiNetworkSsidProperty::get(int idx, char *buffer, size_t max) { + strncpy(buffer, + mWn->getSsid() ? mWn->getSsid() : "none", + max); + return 0; +} +int WifiNetwork::WifiNetworkSsidProperty::set(int idx, const char *value) { + return mWn->setSsid(value); +} + +WifiNetwork::WifiNetworkBssidProperty::WifiNetworkBssidProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "Bssid", false, 1) { +} +int WifiNetwork::WifiNetworkBssidProperty::get(int idx, char *buffer, size_t max) { + strncpy(buffer, + mWn->getBssid() ? mWn->getBssid() : "none", + max); return 0; } +int WifiNetwork::WifiNetworkBssidProperty::set(int idx, const char *value) { + return mWn->setBssid(value); +} + +WifiNetwork::WifiNetworkPskProperty::WifiNetworkPskProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "Psk", false, 1) { +} +int WifiNetwork::WifiNetworkPskProperty::get(int idx, char *buffer, size_t max) { + strncpy(buffer, + mWn->getPsk() ? mWn->getPsk() : "none", + max); + return 0; +} +int WifiNetwork::WifiNetworkPskProperty::set(int idx, const char *value) { + return mWn->setPsk(value); +} + +WifiNetwork::WifiNetworkWepKeyProperty::WifiNetworkWepKeyProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "WepKey", false, 4) { +} + +int WifiNetwork::WifiNetworkWepKeyProperty::get(int idx, char *buffer, size_t max) { + const char *key = mWn->getWepKey(idx); + + strncpy(buffer, (key ? key : "none"), max); + return 0; +} +int WifiNetwork::WifiNetworkWepKeyProperty::set(int idx, const char *value) { + return mWn->setWepKey(idx, value); +} + +WifiNetwork::WifiNetworkDefaultKeyIndexProperty::WifiNetworkDefaultKeyIndexProperty(WifiNetwork *wn) : + WifiNetworkIntegerProperty(wn, "DefaultKeyIndex", false, 1) { +} +int WifiNetwork::WifiNetworkDefaultKeyIndexProperty::get(int idx, int *buffer) { + *buffer = mWn->getDefaultKeyIndex(); + return 0; +} +int WifiNetwork::WifiNetworkDefaultKeyIndexProperty::set(int idx, int value) { + return mWn->setDefaultKeyIndex(value); +} + +WifiNetwork::WifiNetworkPriorityProperty::WifiNetworkPriorityProperty(WifiNetwork *wn) : + WifiNetworkIntegerProperty(wn, "Priority", false, 1) { +} +int WifiNetwork::WifiNetworkPriorityProperty::get(int idx, int *buffer) { + *buffer = mWn->getPriority(); + return 0; +} +int WifiNetwork::WifiNetworkPriorityProperty::set(int idx, int value) { + return mWn->setPriority(value); +} + +WifiNetwork::WifiNetworkKeyManagementProperty::WifiNetworkKeyManagementProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "KeyManagement", false, 1) { +} +int WifiNetwork::WifiNetworkKeyManagementProperty::get(int idx, char *buffer, size_t max) { + + if (mWn->getKeyManagement() == KeyManagementMask::NONE) + strncpy(buffer, "NONE", max); + else { + char tmp[80] = { '\0' }; + + if (mWn->getKeyManagement() & KeyManagementMask::WPA_PSK) + strcat(tmp, "WPA-PSK"); + if (mWn->getKeyManagement() & KeyManagementMask::WPA_EAP) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "WPA-EAP"); + } + if (mWn->getKeyManagement() & KeyManagementMask::IEEE8021X) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "IEEE8021X"); + } + if (tmp[0] == '\0') { + strncpy(buffer, "(internal error)", max); + errno = ENOENT; + return -1; + } + if (tmp[strlen(tmp)] == ' ') + tmp[strlen(tmp)] = '\0'; + + strncpy(buffer, tmp, max); + } + return 0; +} +int WifiNetwork::WifiNetworkKeyManagementProperty::set(int idx, const char *value) { + uint32_t mask; + if (mWn->parseKeyManagementMask(value, &mask)) + return -1; + return mWn->setKeyManagement(mask); +} + +WifiNetwork::WifiNetworkProtocolsProperty::WifiNetworkProtocolsProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "Protocols", false, 1) { +} +int WifiNetwork::WifiNetworkProtocolsProperty::get(int idx, char *buffer, size_t max) { + char tmp[80] = { '\0' }; + + if (mWn->getProtocols() & SecurityProtocolMask::WPA) + strcat(tmp, "WPA"); + if (mWn->getProtocols() & SecurityProtocolMask::RSN) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "RSN"); + } + + if (tmp[0] == '\0') { + strncpy(buffer, "(internal error)", max); + errno = ENOENT; + return NULL; + } + if (tmp[strlen(tmp)] == ' ') + tmp[strlen(tmp)] = '\0'; + + strncpy(buffer, tmp, max); + return 0; +} +int WifiNetwork::WifiNetworkProtocolsProperty::set(int idx, const char *value) { + uint32_t mask; + if (mWn->parseProtocolsMask(value, &mask)) + return -1; + return mWn->setProtocols(mask); +} + +WifiNetwork::WifiNetworkAuthAlgorithmsProperty::WifiNetworkAuthAlgorithmsProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "AuthAlgorithms", false, 1) { +} +int WifiNetwork::WifiNetworkAuthAlgorithmsProperty::get(int idx, char *buffer, size_t max) { + char tmp[80] = { '\0' }; + + if (mWn->getAuthAlgorithms() == 0) { + strncpy(buffer, "NONE", max); + return 0; + } + + if (mWn->getAuthAlgorithms() & AuthenticationAlgorithmMask::OPEN) + strcat(tmp, "OPEN"); + if (mWn->getAuthAlgorithms() & AuthenticationAlgorithmMask::SHARED) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "SHARED"); + } + if (mWn->getAuthAlgorithms() & AuthenticationAlgorithmMask::LEAP) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "LEAP"); + } + + if (tmp[0] == '\0') { + strncpy(buffer, "(internal error)", max); + errno = ENOENT; + return NULL; + } + if (tmp[strlen(tmp)] == ' ') + tmp[strlen(tmp)] = '\0'; + + strncpy(buffer, tmp, max); + return 0; +} +int WifiNetwork::WifiNetworkAuthAlgorithmsProperty::set(int idx, const char *value) { + uint32_t mask; + if (mWn->parseAuthAlgorithmsMask(value, &mask)) + return -1; + return mWn->setAuthAlgorithms(mask); +} + +WifiNetwork::WifiNetworkPairwiseCiphersProperty::WifiNetworkPairwiseCiphersProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "PairwiseCiphers", false, 1) { +} +int WifiNetwork::WifiNetworkPairwiseCiphersProperty::get(int idx, char *buffer, size_t max) { + if (mWn->getPairwiseCiphers() == PairwiseCiphersMask::NONE) + strncpy(buffer, "NONE", max); + else { + char tmp[80] = { '\0' }; + + if (mWn->getPairwiseCiphers() & PairwiseCiphersMask::TKIP) + strcat(tmp, "TKIP"); + if (mWn->getPairwiseCiphers() & PairwiseCiphersMask::CCMP) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "CCMP"); + } + if (tmp[0] == '\0') { + strncpy(buffer, "(internal error)", max); + errno = ENOENT; + return NULL; + } + if (tmp[strlen(tmp)] == ' ') + tmp[strlen(tmp)] = '\0'; + + strncpy(buffer, tmp, max); + } + return 0; +} +int WifiNetwork::WifiNetworkPairwiseCiphersProperty::set(int idx, const char *value) { + uint32_t mask; + if (mWn->parsePairwiseCiphersMask(value, &mask)) + return -1; + return mWn->setPairwiseCiphers(mask); +} + +WifiNetwork::WifiNetworkGroupCiphersProperty::WifiNetworkGroupCiphersProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "GroupCiphers", false, 1) { +} +int WifiNetwork::WifiNetworkGroupCiphersProperty::get(int idx, char *buffer, size_t max) { + char tmp[80] = { '\0' }; + + if (mWn->getGroupCiphers() & GroupCiphersMask::WEP40) + strcat(tmp, "WEP40"); + if (mWn->getGroupCiphers() & GroupCiphersMask::WEP104) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "WEP104"); + } + if (mWn->getGroupCiphers() & GroupCiphersMask::TKIP) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "TKIP"); + } + if (mWn->getGroupCiphers() & GroupCiphersMask::CCMP) { + if (tmp[0] != '\0') + strcat(tmp, " "); + strcat(tmp, "CCMP"); + } + + if (tmp[0] == '\0') { + strncpy(buffer, "(internal error)", max); + errno = ENOENT; + return -1; + } + if (tmp[strlen(tmp)] == ' ') + tmp[strlen(tmp)] = '\0'; + + strncpy(buffer, tmp, max); + return 0; +} +int WifiNetwork::WifiNetworkGroupCiphersProperty::set(int idx, const char *value) { + uint32_t mask; + if (mWn->parseGroupCiphersMask(value, &mask)) + return -1; + return mWn->setGroupCiphers(mask); +} + +WifiNetwork::WifiNetworkHiddenSsidProperty::WifiNetworkHiddenSsidProperty(WifiNetwork *wn) : + WifiNetworkStringProperty(wn, "HiddenSsid", false, 1) { +} +int WifiNetwork::WifiNetworkHiddenSsidProperty::get(int idx, char *buffer, size_t max) { + const char *scan_ssid = mWn->getHiddenSsid(); + + strncpy(buffer, (scan_ssid ? scan_ssid : "none"), max); + return 0; +} +int WifiNetwork::WifiNetworkHiddenSsidProperty::set(int idx, const char *value) { + return mWn->setHiddenSsid(value); +} diff --git a/nexus/WifiNetwork.h b/nexus/WifiNetwork.h index c2f5d235a8f..15ec647eaa4 100644 --- a/nexus/WifiNetwork.h +++ b/nexus/WifiNetwork.h @@ -21,6 +21,10 @@ #include +#include "Property.h" + +class PropertyManager; + class KeyManagementMask { public: static const uint32_t UNKNOWN = 0; @@ -60,19 +64,140 @@ class GroupCiphersMask { }; class Supplicant; -class InterfaceConfig; class Controller; class WifiController; -#include "IPropertyProvider.h" - -class WifiNetwork : public IPropertyProvider{ -public: - static const char *PropertyNames[]; +class WifiNetwork { + class WifiNetworkIntegerProperty : public IntegerProperty { + protected: + WifiNetwork *mWn; + public: + WifiNetworkIntegerProperty(WifiNetwork *wn, const char *name, bool ro, + int elements); + virtual ~WifiNetworkIntegerProperty() {} + virtual int set(int idx, int value) = 0; + virtual int get(int idx, int *buffer) = 0; + }; + friend class WifiNetwork::WifiNetworkIntegerProperty; + + class WifiNetworkStringProperty : public StringProperty { + protected: + WifiNetwork *mWn; + public: + WifiNetworkStringProperty(WifiNetwork *wn, const char *name, bool ro, + int elements); + virtual ~WifiNetworkStringProperty() {} + virtual int set(int idx, const char *value) = 0; + virtual int get(int idx, char *buffer, size_t max) = 0; + }; + friend class WifiNetwork::WifiNetworkStringProperty; + + class WifiNetworkEnabledProperty : public WifiNetworkIntegerProperty { + public: + WifiNetworkEnabledProperty(WifiNetwork *wn); + virtual ~WifiNetworkEnabledProperty() {}; + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiNetworkPriorityProperty : public WifiNetworkIntegerProperty { + public: + WifiNetworkPriorityProperty(WifiNetwork *wn); + virtual ~WifiNetworkPriorityProperty() {}; + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiNetworkDefaultKeyIndexProperty : public WifiNetworkIntegerProperty { + public: + WifiNetworkDefaultKeyIndexProperty(WifiNetwork *wn); + virtual ~WifiNetworkDefaultKeyIndexProperty() {}; + int set(int idx, int value); + int get(int idx, int *buffer); + }; + + class WifiNetworkSsidProperty : public WifiNetworkStringProperty { + public: + WifiNetworkSsidProperty(WifiNetwork *wn); + virtual ~WifiNetworkSsidProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkBssidProperty : public WifiNetworkStringProperty { + public: + WifiNetworkBssidProperty(WifiNetwork *wn); + virtual ~WifiNetworkBssidProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkPskProperty : public WifiNetworkStringProperty { + public: + WifiNetworkPskProperty(WifiNetwork *wn); + virtual ~WifiNetworkPskProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkKeyManagementProperty : public WifiNetworkStringProperty { + public: + WifiNetworkKeyManagementProperty(WifiNetwork *wn); + virtual ~WifiNetworkKeyManagementProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkAuthAlgorithmsProperty : public WifiNetworkStringProperty { + public: + WifiNetworkAuthAlgorithmsProperty(WifiNetwork *wn); + virtual ~WifiNetworkAuthAlgorithmsProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkProtocolsProperty : public WifiNetworkStringProperty { + public: + WifiNetworkProtocolsProperty(WifiNetwork *wn); + virtual ~WifiNetworkProtocolsProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkWepKeyProperty : public WifiNetworkStringProperty { + public: + WifiNetworkWepKeyProperty(WifiNetwork *wn); + virtual ~WifiNetworkWepKeyProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkPairwiseCiphersProperty : public WifiNetworkStringProperty { + public: + WifiNetworkPairwiseCiphersProperty(WifiNetwork *wn); + virtual ~WifiNetworkPairwiseCiphersProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkGroupCiphersProperty : public WifiNetworkStringProperty { + public: + WifiNetworkGroupCiphersProperty(WifiNetwork *wn); + virtual ~WifiNetworkGroupCiphersProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; + + class WifiNetworkHiddenSsidProperty : public WifiNetworkStringProperty { + public: + WifiNetworkHiddenSsidProperty(WifiNetwork *wn); + virtual ~WifiNetworkHiddenSsidProperty() {}; + int set(int idx, const char *value); + int get(int idx, char *buffer, size_t max); + }; private: Supplicant *mSuppl; - InterfaceConfig *mIfaceCfg; WifiController *mController; /* @@ -128,33 +253,49 @@ class WifiNetwork : public IPropertyProvider{ /* * The set of key management protocols supported by this configuration. */ - uint32_t mAllowedKeyManagement; + uint32_t mKeyManagement; /* * The set of security protocols supported by this configuration. */ - uint32_t mAllowedProtocols; + uint32_t mProtocols; /* * The set of authentication protocols supported by this configuration. */ - uint32_t mAllowedAuthAlgorithms; + uint32_t mAuthAlgorithms; /* * The set of pairwise ciphers for WPA supported by this configuration. */ - uint32_t mAllowedPairwiseCiphers; + uint32_t mPairwiseCiphers; /* * The set of group ciphers for WPA supported by this configuration. */ - uint32_t mAllowedGroupCiphers; + uint32_t mGroupCiphers; /* * Set if this Network is enabled */ bool mEnabled; + char *mPropNamespace; + struct { + WifiNetworkEnabledProperty *propEnabled; + WifiNetworkSsidProperty *propSsid; + WifiNetworkBssidProperty *propBssid; + WifiNetworkPskProperty *propPsk; + WifiNetworkWepKeyProperty *propWepKey; + WifiNetworkDefaultKeyIndexProperty *propDefKeyIdx; + WifiNetworkPriorityProperty *propPriority; + WifiNetworkKeyManagementProperty *propKeyManagement; + WifiNetworkProtocolsProperty *propProtocols; + WifiNetworkAuthAlgorithmsProperty *propAuthAlgorithms; + WifiNetworkPairwiseCiphersProperty *propPairwiseCiphers; + WifiNetworkGroupCiphersProperty *propGroupCiphers; + WifiNetworkHiddenSsidProperty *propHiddenSsid; + } mStaticProperties; private: WifiNetwork(); @@ -165,8 +306,8 @@ class WifiNetwork : public IPropertyProvider{ virtual ~WifiNetwork(); WifiNetwork *clone(); - int registerProperties(); - int unregisterProperties(); + int attachProperties(PropertyManager *pm, const char *nsName); + int detachProperties(PropertyManager *pm, const char *nsName); int getNetworkId() { return mNetid; } const char *getSsid() { return mSsid; } @@ -176,19 +317,14 @@ class WifiNetwork : public IPropertyProvider{ int getDefaultKeyIndex() { return mDefaultKeyIndex; } int getPriority() { return mPriority; } const char *getHiddenSsid() { return mHiddenSsid; } - uint32_t getAllowedKeyManagement() { return mAllowedKeyManagement; } - uint32_t getAllowedProtocols() { return mAllowedProtocols; } - uint32_t getAllowedAuthAlgorithms() { return mAllowedAuthAlgorithms; } - uint32_t getAllowedPairwiseCiphers() { return mAllowedPairwiseCiphers; } - uint32_t getAllowedGroupCiphers() { return mAllowedGroupCiphers; } + uint32_t getKeyManagement() { return mKeyManagement; } + uint32_t getProtocols() { return mProtocols; } + uint32_t getAuthAlgorithms() { return mAuthAlgorithms; } + uint32_t getPairwiseCiphers() { return mPairwiseCiphers; } + uint32_t getGroupCiphers() { return mGroupCiphers; } bool getEnabled() { return mEnabled; } Controller *getController() { return (Controller *) mController; } - int set(const char *name, const char *value); - const char *get(const char *name, char *buffer, size_t maxsize); - - InterfaceConfig *getIfaceCfg() { return mIfaceCfg; } - int setEnabled(bool enabled); int setSsid(const char *ssid); int setBssid(const char *bssid); @@ -197,14 +333,22 @@ class WifiNetwork : public IPropertyProvider{ int setDefaultKeyIndex(int idx); int setPriority(int pri); int setHiddenSsid(const char *ssid); - int setAllowedKeyManagement(uint32_t mask); - int setAllowedProtocols(uint32_t mask); - int setAllowedAuthAlgorithms(uint32_t mask); - int setAllowedPairwiseCiphers(uint32_t mask); - int setAllowedGroupCiphers(uint32_t mask); + int setKeyManagement(uint32_t mask); + int setProtocols(uint32_t mask); + int setAuthAlgorithms(uint32_t mask); + int setPairwiseCiphers(uint32_t mask); + int setGroupCiphers(uint32_t mask); // XXX:Should this really be exposed?.. meh int refresh(); + +private: + int parseKeyManagementMask(const char *buffer, uint32_t *mask); + int parseProtocolsMask(const char *buffer, uint32_t *mask); + int parseAuthAlgorithmsMask(const char *buffer, uint32_t *mask); + int parsePairwiseCiphersMask(const char *buffer, uint32_t *mask); + int parseGroupCiphersMask(const char *buffer, uint32_t *mask); + void createProperties(); }; typedef android::List WifiNetworkCollection; diff --git a/nexus/WifiStatusPoller.cpp b/nexus/WifiStatusPoller.cpp new file mode 100644 index 00000000000..cf717337e81 --- /dev/null +++ b/nexus/WifiStatusPoller.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "WifiStatusPoller" +#include + +#include "WifiStatusPoller.h" +#include "IWifiStatusPollerHandler.h" + + +WifiStatusPoller::WifiStatusPoller(IWifiStatusPollerHandler *handler) : + mHandlers(handler) { + mPollingInterval = 5; + mStarted = false; +} + +int WifiStatusPoller::start() { + + if (pipe(mCtrlPipe)) + return -1; + + if (pthread_create(&mThread, NULL, WifiStatusPoller::threadStart, this)) + return -1; + + return 0; +} + +int WifiStatusPoller::stop() { + char c = 0; + + if (write(mCtrlPipe[1], &c, 1) != 1) { + LOGE("Error writing to control pipe (%s)", strerror(errno)); + return -1; + } + + void *ret; + if (pthread_join(mThread, &ret)) { + LOGE("Error joining to listener thread (%s)", strerror(errno)); + return -1; + } + close(mCtrlPipe[0]); + close(mCtrlPipe[1]); + return 0; +} + +void *WifiStatusPoller::threadStart(void *obj) { + WifiStatusPoller *me = reinterpret_cast(obj); + + me->mStarted = true; + LOGD("Starting"); + me->run(); + me->mStarted = false; + LOGD("Stopping"); + pthread_exit(NULL); + return NULL; +} + +void WifiStatusPoller::run() { + + while(1) { + struct timeval to; + fd_set read_fds; + int rc = 0; + int max = 0; + + FD_ZERO(&read_fds); + to.tv_usec = 0; + to.tv_sec = mPollingInterval; + + FD_SET(mCtrlPipe[0], &read_fds); + max = mCtrlPipe[0]; + + if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) { + LOGE("select failed (%s)", strerror(errno)); + sleep(1); + continue; + } else if (!rc) { + mHandlers->onStatusPollInterval(); + } + if (FD_ISSET(mCtrlPipe[0], &read_fds)) + break; + } +} diff --git a/nexus/WifiStatusPoller.h b/nexus/WifiStatusPoller.h new file mode 100644 index 00000000000..202bbbf0090 --- /dev/null +++ b/nexus/WifiStatusPoller.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WIFI_STATUS_POLLER_H +#define _WIFI_STATUS_POLLER_H + +#include + +class IWifiStatusPollerHandler; + +class WifiStatusPoller { + pthread_t mThread; + int mCtrlPipe[2]; + int mPollingInterval; + IWifiStatusPollerHandler *mHandlers; + bool mStarted; + +public: + WifiStatusPoller(IWifiStatusPollerHandler *handler); + virtual ~WifiStatusPoller() {} + + int start(); + int stop(); + bool isStarted() { return mStarted; } + + void setPollingInterval(int interval); + int getPollingInterval() { return mPollingInterval; } + +private: + static void *threadStart(void *obj); + void run(); +}; + +#endif diff --git a/rootdir/Android.mk b/rootdir/Android.mk index db98fab013d..3bb226211e0 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -5,9 +5,20 @@ include $(CLEAR_VARS) copy_from := \ etc/dbus.conf \ - etc/init.goldfish.sh \ etc/hosts +ifeq ($(TARGET_PRODUCT),generic) +copy_from += etc/vold.conf +endif + +# the /system/etc/init.goldfish.sh is needed to enable emulator support +# in the system image. In theory, we don't need these for -user builds +# which are device-specific. However, these builds require at the moment +# to run the dex pre-optimization *in* the emulator. So keep the file until +# we are capable of running dex preopt on the host. +# +copy_from += etc/init.goldfish.sh + copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from)) copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from)) @@ -28,11 +39,13 @@ $(file) : $(LOCAL_PATH)/init.rc | $(ACP) ALL_PREBUILT += $(file) endif +# Just like /system/etc/init.goldfish.sh, the /init.godlfish.rc is here +# to allow -user builds to properly run the dex pre-optimization pass in +# the emulator. file := $(TARGET_ROOT_OUT)/init.goldfish.rc $(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP) $(transform-prebuilt-to-target) ALL_PREBUILT += $(file) - # create some directories (some are mount points) DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \ diff --git a/rootdir/etc/vold.conf b/rootdir/etc/vold.conf new file mode 100644 index 00000000000..4e045090ebf --- /dev/null +++ b/rootdir/etc/vold.conf @@ -0,0 +1,10 @@ +## vold configuration file for the 'generic' target + +volume_sdcard { + ## This is the direct uevent device path to the SD slot on the device + media_path /devices/platform/goldfish_mmc.0/mmc_host/mmc0 + + media_type mmc + mount_point /sdcard + ums_path /devices/platform/usb_mass_storage/lun0 +} diff --git a/rootdir/init.rc b/rootdir/init.rc index 2bed980293d..f62d1d816b7 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -17,12 +17,14 @@ loglevel 3 # Backward compatibility symlink /system/etc /etc + symlink /sys/kernel/debug /d # create mountpoints and mount tmpfs on sqlite_stmt_journals mkdir /sdcard 0000 system system mkdir /system mkdir /data 0771 system system mkdir /cache 0770 system cache + mkdir /config 0500 root root mkdir /sqlite_stmt_journals 01777 root root mount tmpfs tmpfs /sqlite_stmt_journals size=4m @@ -34,6 +36,7 @@ loglevel 3 write /proc/sys/kernel/sched_latency_ns 10000000 write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000 write /proc/sys/kernel/sched_compat_yield 1 + write /proc/sys/kernel/sched_child_runs_first 0 # Create cgroup mount points for process groups mkdir /dev/cpuctl @@ -64,6 +67,30 @@ loglevel 3 chown system system /data chmod 0771 /data + # Create dump dir and collect dumps. + # Do this before we mount cache so eventually we can use cache for + # storing dumps on platforms which do not have a dedicated dump partition. + + mkdir /data/dontpanic + chown root log /data/dontpanic + chmod 0750 /data/dontpanic + + # Collect apanic data, free resources and re-arm trigger + copy /proc/apanic_console /data/dontpanic/apanic_console + chown root log /data/dontpanic/apanic_console + chmod 0640 /data/dontpanic/apanic_console + + copy /proc/apanic_threads /data/dontpanic/apanic_threads + chown root log /data/dontpanic/apanic_threads + chmod 0640 /data/dontpanic/apanic_threads + + write /proc/apanic_console 1 + + # Collect ramconsole data + copy /proc/last_kmsg /data/dontpanic/last_kmsg + chown root log /data/dontpanic/last_kmsg + chmod 0640 /data/dontpanic/last_kmsg + # Same reason as /data above mount yaffs2 mtd@cache /cache nosuid nodev chown system cache /cache @@ -73,10 +100,14 @@ loglevel 3 chown system system /cache/recovery chmod 0770 /cache/recovery + #change permissions on vmallocinfo so we can grab it from bugreports + chown root log /proc/vmallocinfo + chmod 0440 /proc/vmallocinfo + # create basic filesystem structure mkdir /data/misc 01771 system misc - mkdir /data/misc/hcid 0770 bluetooth bluetooth - mkdir /data/misc/keystore 0770 keystore keystore + mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth + mkdir /data/misc/keystore 0700 keystore keystore mkdir /data/misc/vpn 0770 system system mkdir /data/misc/vpn/profiles 0770 system system # give system access to wpa_supplicant.conf for backup and restore @@ -90,6 +121,7 @@ loglevel 3 mkdir /data/app 0771 system system mkdir /data/property 0700 root root + # create dalvik-cache and double-check the perms mkdir /data/dalvik-cache 0771 system system chown system system /data/dalvik-cache @@ -148,6 +180,10 @@ on boot # Set init its forked children's oom_adj. write /proc/1/oom_adj -16 + # Tweak background writeout + write /proc/sys/vm/dirty_expire_centisecs 200 + write /proc/sys/vm/dirty_background_ratio 5 + # Permissions for System Server and daemons. chown radio system /sys/android_power/state chown radio system /sys/android_power/request_state @@ -238,12 +274,13 @@ service ril-daemon /system/bin/rild socket rild stream 660 root radio socket rild-debug stream 660 radio system user root - group radio cache inet misc + group radio cache inet misc audio service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on + onrestart restart media service media /system/bin/mediaserver user media @@ -265,11 +302,11 @@ service dbus /system/bin/dbus-daemon --system --nofork user bluetooth group bluetooth net_bt_admin -service hcid /system/bin/hcid -s -n -f /etc/bluez/hcid.conf +service bluetoothd /system/bin/bluetoothd -n socket bluetooth stream 660 bluetooth bluetooth socket dbus_bluetooth stream 660 bluetooth bluetooth # init.rc does not yet support applying capabilities, so run as root and - # let hcid drop uid to bluetooth with the right linux capabilities + # let bluetoothd drop uid to bluetooth with the right linux capabilities group bluetooth net_bt_admin misc disabled @@ -285,6 +322,18 @@ service hsag /system/bin/sdptool add --channel=11 HSAG disabled oneshot +service opush /system/bin/sdptool add --channel=12 OPUSH + user bluetooth + group bluetooth net_bt_admin + disabled + oneshot + +service pbap /system/bin/sdptool add --channel=19 PBAP + user bluetooth + group bluetooth net_bt_admin + disabled + oneshot + service installd /system/bin/installd socket installd stream 600 system system @@ -294,7 +343,7 @@ service flash_recovery /system/etc/install-recovery.sh service racoon /system/bin/racoon socket racoon stream 600 system system # racoon will setuid to vpn after getting necessary resources. - group net_admin keystore + group net_admin disabled oneshot @@ -305,8 +354,12 @@ service mtpd /system/bin/mtpd disabled oneshot -service keystore /system/bin/keystore +service keystore /system/bin/keystore /data/misc/keystore user keystore group keystore socket keystore stream 666 +service dumpstate /system/bin/dumpstate -s + socket dumpstate stream 0660 shell log + disabled + oneshot diff --git a/toolbox/ls.c b/toolbox/ls.c index f609df21cb8..b221074ae4e 100644 --- a/toolbox/ls.c +++ b/toolbox/ls.c @@ -15,9 +15,11 @@ #include // bits for flags argument -#define LIST_LONG (1 << 0) -#define LIST_ALL (1 << 1) -#define LIST_RECURSIVE (1 << 2) +#define LIST_LONG (1 << 0) +#define LIST_ALL (1 << 1) +#define LIST_RECURSIVE (1 << 2) +#define LIST_DIRECTORIES (1 << 3) +#define LIST_SIZE (1 << 4) // fwd static int listpath(const char *name, int flags); @@ -84,7 +86,19 @@ static void group2str(unsigned gid, char *out) } } -static int listfile(const char *path, int flags) +static int listfile_size(const char *path, int flags) +{ + struct stat s; + + if (lstat(path, &s) < 0) + return -1; + + /* blocks are 512 bytes, we want output to be KB */ + printf("%lld %s\n", s.st_blocks / 2, path); + return 0; +} + +static int listfile_long(const char *path, int flags) { struct stat s; char date[32]; @@ -155,6 +169,30 @@ static int listfile(const char *path, int flags) return 0; } +static int listfile(const char *dirname, const char *filename, int flags) +{ + if ((flags & (LIST_LONG | LIST_SIZE)) == 0) { + printf("%s\n", filename); + return 0; + } + + char tmp[4096]; + const char* pathname = filename; + + if (dirname != NULL) { + snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename); + pathname = tmp; + } else { + pathname = filename; + } + + if ((flags & LIST_LONG) != 0) { + return listfile_long(pathname, flags); + } else /*((flags & LIST_SIZE) != 0)*/ { + return listfile_size(pathname, flags); + } +} + static int listdir(const char *name, int flags) { char tmp[4096]; @@ -170,12 +208,8 @@ static int listdir(const char *name, int flags) while((de = readdir(d)) != 0){ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; - if ((flags & LIST_LONG) != 0) { - sprintf(tmp, "%s/%s", name, de->d_name); - listfile(tmp, flags); - } else { - printf("%s\n", de->d_name); - } + + listfile(name, de->d_name, flags); } if (flags & LIST_RECURSIVE) { @@ -190,8 +224,10 @@ static int listdir(const char *name, int flags) if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; - if (!strcmp(name, "/")) sprintf(tmp, "/%s", de->d_name); - else sprintf(tmp, "%s/%s", name, de->d_name); + if (!strcmp(name, "/")) + snprintf(tmp, sizeof(tmp), "/%s", de->d_name); + else + snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name); /* * If the name ends in a '/', use stat() so we treat it like a @@ -238,18 +274,13 @@ static int listpath(const char *name, int flags) return -1; } - if (S_ISDIR(s.st_mode)) { + if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) { if (flags & LIST_RECURSIVE) printf("\n%s:\n", name); return listdir(name, flags); } else { - if ((flags & LIST_LONG) != 0) { - /* yeah this calls stat() again*/ - return listfile(name, flags); - } else { - printf("%s\n", name); - return 0; - } + /* yeah this calls stat() again*/ + return listfile(NULL, name, flags); } } @@ -263,12 +294,16 @@ int ls_main(int argc, char **argv) int err = 0; for (i = 1; i < argc; i++) { - if(!strcmp(argv[i], "-l")) { + if (!strcmp(argv[i], "-l")) { flags |= LIST_LONG; + } else if (!strcmp(argv[i], "-s")) { + flags |= LIST_SIZE; } else if (!strcmp(argv[i], "-a")) { flags |= LIST_ALL; } else if (!strcmp(argv[i], "-R")) { flags |= LIST_RECURSIVE; + } else if (!strcmp(argv[i], "-d")) { + flags |= LIST_DIRECTORIES; } else { listed++; if(listpath(argv[i], flags) != 0) { diff --git a/toolbox/mount.c b/toolbox/mount.c index 86047a9ddd4..472c952e765 100644 --- a/toolbox/mount.c +++ b/toolbox/mount.c @@ -138,14 +138,17 @@ do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int if (loop) { int file_fd, device_fd; + int flags; + + flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR; // FIXME - only one loop mount supported at a time - file_fd = open(dev, O_RDWR); + file_fd = open(dev, flags); if (file_fd < -1) { perror("open backing file failed"); return 1; } - device_fd = open(LOOP_DEVICE, O_RDWR); + device_fd = open(LOOP_DEVICE, flags); if (device_fd < -1) { perror("open loop device failed"); close(file_fd); diff --git a/toolbox/ps.c b/toolbox/ps.c index 3b86fa252b1..bc50cfa971e 100644 --- a/toolbox/ps.c +++ b/toolbox/ps.c @@ -11,6 +11,8 @@ #include +#include + static char *nexttoksep(char **strp, char *sep) { @@ -24,6 +26,7 @@ static char *nexttok(char **strp) #define SHOW_PRIO 1 #define SHOW_TIME 2 +#define SHOW_POLICY 4 static int display_flags = 0; @@ -138,12 +141,26 @@ static int ps_line(int pid, int tid, char *namefilter) } if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) { - printf("%-8s %-5d %-5d %-5d %-5d", user, pid, ppid, vss / 1024, rss * 4); + printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4); if(display_flags&SHOW_PRIO) printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched); + if (display_flags & SHOW_POLICY) { + SchedPolicy p; + if (get_sched_policy(pid, &p) < 0) + printf(" un "); + else { + if (p == SP_BACKGROUND) + printf(" bg "); + else if (p == SP_FOREGROUND) + printf(" fg "); + else + printf(" er "); + } + } printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name); if(display_flags&SHOW_TIME) printf(" (u:%d, s:%d)", utime, stime); + printf("\n"); } return 0; @@ -186,6 +203,8 @@ int ps_main(int argc, char **argv) threads = 1; } else if(!strcmp(argv[1],"-x")) { display_flags |= SHOW_TIME; + } else if(!strcmp(argv[1],"-P")) { + display_flags |= SHOW_POLICY; } else if(!strcmp(argv[1],"-p")) { display_flags |= SHOW_PRIO; } else if(isdigit(argv[1][0])){ @@ -197,8 +216,9 @@ int ps_main(int argc, char **argv) argv++; } - printf("USER PID PPID VSIZE RSS %sWCHAN PC NAME\n", - (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":""); + printf("USER PID PPID VSIZE RSS %s %s WCHAN PC NAME\n", + (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"", + (display_flags&SHOW_POLICY)?"PCY " : ""); while((de = readdir(d)) != 0){ if(isdigit(de->d_name[0])){ int pid = atoi(de->d_name); diff --git a/toolbox/smd.c b/toolbox/smd.c index 65ff994e5ce..91e495c3fc8 100644 --- a/toolbox/smd.c +++ b/toolbox/smd.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/toolbox/top.c b/toolbox/top.c index dcc08434479..daade6d646c 100644 --- a/toolbox/top.c +++ b/toolbox/top.c @@ -39,6 +39,8 @@ #include #include +#include + struct cpu_info { long unsigned utime, ntime, stime, itime; long unsigned iowtime, irqtime, sirqtime; @@ -64,6 +66,7 @@ struct proc_info { long vss; long rss; int num_threads; + char policy[32]; }; struct proc_list { @@ -88,6 +91,7 @@ static struct proc_info *alloc_proc(void); static void free_proc(struct proc_info *proc); static void read_procs(void); static int read_stat(char *filename, struct proc_info *proc); +static void read_policy(int pid, struct proc_info *proc); static void add_proc(int proc_num, struct proc_info *proc); static int read_cmdline(char *filename, struct proc_info *proc); static int read_status(char *filename, struct proc_info *proc); @@ -260,6 +264,8 @@ static void read_procs(void) { sprintf(filename, "/proc/%d/status", pid); read_status(filename, proc); + read_policy(pid, proc); + proc->num_threads = 0; } else { sprintf(filename, "/proc/%d/cmdline", pid); @@ -289,6 +295,8 @@ static void read_procs(void) { sprintf(filename, "/proc/%d/task/%d/stat", pid, tid); read_stat(filename, proc); + read_policy(tid, proc); + strcpy(proc->name, cur_proc.name); proc->uid = cur_proc.uid; proc->gid = cur_proc.gid; @@ -368,6 +376,20 @@ static int read_cmdline(char *filename, struct proc_info *proc) { return 0; } +static void read_policy(int pid, struct proc_info *proc) { + SchedPolicy p; + if (get_sched_policy(pid, &p) < 0) + strcpy(proc->policy, "unk"); + else { + if (p == SP_BACKGROUND) + strcpy(proc->policy, "bg"); + else if (p == SP_FOREGROUND) + strcpy(proc->policy, "fg"); + else + strcpy(proc->policy, "er"); + } +} + static int read_status(char *filename, struct proc_info *proc) { FILE *file; char line[MAX_LINE]; @@ -432,9 +454,9 @@ static void print_procs(void) { total_delta_time); printf("\n"); if (!threads) - printf("%5s %4s %1s %5s %7s %7s %-8s %s\n", "PID", "CPU%", "S", "#THR", "VSS", "RSS", "UID", "Name"); + printf("%5s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name"); else - printf("%5s %5s %4s %1s %7s %7s %-8s %-15s %s\n", "PID", "TID", "CPU%", "S", "VSS", "RSS", "UID", "Thread", "Proc"); + printf("%5s %5s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc"); for (i = 0; i < num_new_procs; i++) { proc = new_procs[i]; @@ -456,11 +478,11 @@ static void print_procs(void) { group_str = group_buf; } if (!threads) - printf("%5d %3ld%% %c %5d %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, - proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name[0] != 0 ? proc->name : proc->tname); + printf("%5d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, + proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname); else - printf("%5d %5d %3ld%% %c %6ldK %6ldK %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->delta_time * 100 / total_delta_time, proc->state, - proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->tname, proc->name); + printf("%5d %5d %3ld%% %c %6ldK %6ldK %3s %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->delta_time * 100 / total_delta_time, proc->state, + proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name); } } diff --git a/vold/blkdev.c b/vold/blkdev.c index e10eafc8082..22d000e5d9c 100644 --- a/vold/blkdev.c +++ b/vold/blkdev.c @@ -32,6 +32,7 @@ #include "vold.h" #include "blkdev.h" #include "diskmbr.h" +#include "media.h" #define DEBUG_BLKDEV 0 @@ -132,7 +133,12 @@ int blkdev_refresh(blkdev_t *blk) } } else if (blk->type == blkdev_partition) { struct dos_partition part; - int part_no = blk->minor -1; + int part_no; + + if (blk->media->media_type == media_mmc) + part_no = blk->minor % MMC_PARTS_PER_CARD -1; + else + part_no = blk->minor -1; if (part_no < 4) { dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part); diff --git a/vold/format.c b/vold/format.c index cd401972f77..c67b358d917 100755 --- a/vold/format.c +++ b/vold/format.c @@ -33,21 +33,23 @@ int format_partition(blkdev_t *part, char *type) { char *devpath; int rc = -EINVAL; - + devpath = blkdev_get_devpath(part); if (!strcmp(type, FORMAT_TYPE_FAT32)) { - char *args[9]; + char *args[7]; args[0] = MKDOSFS_PATH; args[1] = "-F"; - args[2] = "32"; - args[3] = "-c"; - args[4] = "16"; - args[5] = "-O"; - args[6] = "android"; - args[7] = devpath; - args[8] = NULL; - rc = logwrap(8, args, 1); + if ((part->nr_sec * 512) <= (unsigned int) (1024*1024*1024*2)) + args[2] = "16"; + else + args[2] = "32"; + + args[3] = "-O"; + args[4] = "android"; + args[5] = devpath; + args[6] = NULL; + rc = logwrap(7, args, 1); } else { char *args[7]; args[0] = MKE2FS_PATH; diff --git a/vold/media.h b/vold/media.h index 567ce045138..6fd8b8432c0 100644 --- a/vold/media.h +++ b/vold/media.h @@ -28,6 +28,12 @@ typedef enum media_type { media_devmapper, } media_type_t; +/* + * max 8 partitions per card + */ +#define MMC_PARTS_PER_CARD (1<<3) +#define ALIGN_MMC_MINOR(min) (min / MMC_PARTS_PER_CARD * MMC_PARTS_PER_CARD) + typedef struct media { char *devpath; char *name; diff --git a/vold/mmc.c b/vold/mmc.c index cbddb92234b..b321c80f716 100644 --- a/vold/mmc.c +++ b/vold/mmc.c @@ -253,7 +253,7 @@ static int mmc_bootstrap_mmcblk_partition(char *devpath) char filename[255]; char *uevent_buffer; ssize_t sz; - char *uevent_params[4]; + char *uevent_params[5]; char tmp[255]; FILE *fp; char line[255]; diff --git a/vold/uevent.c b/vold/uevent.c index dffe817073e..dc15d80d615 100644 --- a/vold/uevent.c +++ b/vold/uevent.c @@ -325,7 +325,10 @@ static int handle_block_event(struct uevent *event) * If there isn't a disk already its because *we* * are the disk */ - disk = blkdev_lookup_by_devno(maj, 0); + if (media->media_type == media_mmc) + disk = blkdev_lookup_by_devno(maj, ALIGN_MMC_MINOR(min)); + else + disk = blkdev_lookup_by_devno(maj, 0); if (!(blkdev = blkdev_create(disk, event->path, diff --git a/vold/volmgr.c b/vold/volmgr.c index 3c34a9c52d1..deb680e051c 100644 --- a/vold/volmgr.c +++ b/vold/volmgr.c @@ -460,7 +460,7 @@ int volmgr_enable_ums(boolean enable) pthread_mutex_lock(&v->lock); if (v->state == volstate_mounted) volmgr_send_eject_request(v); - else if (v->state == volstate_ums) { + else if (v->state == volstate_ums || v->state == volstate_nomedia) { pthread_mutex_unlock(&v->lock); goto next_vol; } @@ -536,9 +536,16 @@ static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev) * Since we only support creating 1 partition (right now), * we can just lookup the target by devno */ - blkdev_t *part = blkdev_lookup_by_devno(dev->major, 1); + blkdev_t *part; + if (vol->media_type == media_mmc) + part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + 1); + else + part = blkdev_lookup_by_devno(dev->major, 1); if (!part) { - part = blkdev_lookup_by_devno(dev->major, 0); + if (vol->media_type == media_mmc) + part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor)); + else + part = blkdev_lookup_by_devno(dev->major, 0); if (!part) { LOGE("Unable to find device to format"); return -ENODEV; @@ -573,9 +580,14 @@ static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev) rc = -ENODEV; int i; for (i = 0; i < dev->nr_parts; i++) { - blkdev_t *part = blkdev_lookup_by_devno(dev->major, (i+1)); + blkdev_t *part; + if (vol->media_type == media_mmc) + part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + (i+1)); + else + part = blkdev_lookup_by_devno(dev->major, (i+1)); if (!part) { - LOGE("Error - unable to lookup partition for blkdev %d:%d", dev->major, (i+1)); + LOGE("Error - unable to lookup partition for blkdev %d:%d", + dev->major, dev->minor); continue; } rc = _volmgr_start(vol, part); diff --git a/vold/volmgr_vfat.c b/vold/volmgr_vfat.c index 22e2dcf9197..4c695e4ec5e 100644 --- a/vold/volmgr_vfat.c +++ b/vold/volmgr_vfat.c @@ -18,6 +18,7 @@ #include #include +#include #include "vold.h" #include "volmgr.h" @@ -108,14 +109,29 @@ int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) } /* - * The mount masks restrict access so that: - * 1. The 'system' user cannot access the SD card at all - - * (protects system_server from grabbing file references) - * 2. Group users can RWX - * 3. Others can only RX + * Note: This is a temporary hack. If the sampling profiler is enabled, + * we make the SD card world-writable so any process can write snapshots. + * + * TODO: Remove this code once we have a drop box in system_server. */ - rc = mount(devpath, vol->mount_point, "vfat", flags, - "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed"); + char value[PROPERTY_VALUE_MAX]; + property_get("persist.sampling_profiler", value, ""); + if (value[0] == '1') { + LOGW("The SD card is world-writable because the" + " 'persist.sampling_profiler' system property is set to '1'."); + rc = mount(devpath, vol->mount_point, "vfat", flags, + "utf8,uid=1000,gid=1015,fmask=000,dmask=000,shortname=mixed"); + } else { + /* + * The mount masks restrict access so that: + * 1. The 'system' user cannot access the SD card at all - + * (protects system_server from grabbing file references) + * 2. Group users can RWX + * 3. Others can only RX + */ + rc = mount(devpath, vol->mount_point, "vfat", flags, + "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed"); + } if (rc && errno == EROFS) { LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO",