From: Julian Seward Date: Sat, 22 Oct 2011 20:38:08 +0000 (+0000) Subject: Make vgdb.c work on Android, so that the GDB server as a whole X-Git-Tag: svn/VALGRIND_3_7_0~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba88dbd3539be171c9a6ef40ceca3bfd675d596a;p=thirdparty%2Fvalgrind.git Make vgdb.c work on Android, so that the GDB server as a whole will work on Android. Fixes #283600. (Philippe Waroquiers, philippe.waroquiers@skynet.be) git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12204 --- diff --git a/coregrind/m_options.c b/coregrind/m_options.c index 7ae9a7a2b9..a1bceace0c 100644 --- a/coregrind/m_options.c +++ b/coregrind/m_options.c @@ -47,11 +47,7 @@ VexControl VG_(clo_vex_control); Bool VG_(clo_error_limit) = True; Int VG_(clo_error_exitcode) = 0; -#if defined(VGPV_arm_linux_android) -VgVgdb VG_(clo_vgdb) = Vg_VgdbNo; // currently disabled on Android -#else VgVgdb VG_(clo_vgdb) = Vg_VgdbYes; -#endif Int VG_(clo_vgdb_poll) = 5000; Int VG_(clo_vgdb_error) = 999999999; HChar* VG_(clo_vgdb_prefix) = NULL; diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c index e250e93019..3c5c9d6e64 100644 --- a/coregrind/vgdb.c +++ b/coregrind/vgdb.c @@ -26,21 +26,6 @@ The GNU General Public License is contained in the file COPYING. */ -/* Too difficult to make this work on Android right now. Let's - skip for the time being at least. */ -#if defined(VGPV_arm_linux_android) - -#include -int main (int argc, char** argv) -{ - fprintf(stderr, - "%s: is not currently available on Android, sorry.\n", - argv[0]); - return 0; -} - -#else /* all other (Linux?) platforms */ - #include "pub_core_basics.h" #include "pub_core_vki.h" #include "pub_core_libcsetjmp.h" @@ -61,17 +46,14 @@ int main (int argc, char** argv) #include #include #include +#include +#include +#include +#include #include #include #include #include -#include - -#if defined(VGO_linux) -# include -# include -#endif - /* vgdb has two usages: 1. relay application between gdb and the gdbserver embedded in valgrind. 2. standalone to send monitor commands to a running valgrind-ified process @@ -111,6 +93,19 @@ I_die_here : (PTRACEINVOKER) architecture missing in vgdb.c #undef PTRACEINVOKER #endif +#if defined(VGPV_arm_linux_android) +#undef PTRACEINVOKER +#endif + +#if defined(PTRACEINVOKER) +#include +#if defined(VGO_linux) +# include +# include +#endif +#endif + + // Outputs information for the user about ptrace_scope protection // or ptrace not working. static void ptrace_restrictions_msg(void); @@ -1194,11 +1189,8 @@ void *invoke_gdbserver_in_valgrind(void *v_pid) if (usecs == 0 || usecs > 1000 * 1000) usecs = 1000 * 1000; } - if (usleep(usecs) != 0) { - if (errno == EINTR) - continue; - XERROR (errno, "error usleep\n"); - } + usleep(usecs); + /* If nothing happened during our sleep, let's try to wake up valgrind or check for cmd time out. */ if (written_by_vgdb_before_sleep == VS_written_by_vgdb @@ -1272,7 +1264,12 @@ int open_fifo (char* name, int flags, char* desc) static void acquire_lock (int fd, int valgrind_pid) { - if (lockf(fd, F_TLOCK, 1) < 0) { + struct flock fl; + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 1; + if (fcntl(fd, F_SETLK, &fl) < 0) { if (errno == EAGAIN || errno == EACCES) { XERROR(errno, "Cannot acquire lock.\n" @@ -1359,7 +1356,7 @@ char *ppConnectionKind (ConnectionKind con) static char *shared_mem; -static const int from_gdb = 0; +static int from_gdb = 0; /* stdin by default, changed if --port is given. */ static char *from_gdb_to_pid; /* fifo name to write gdb command to pid */ /* Returns True in case read/write operations were done properly. Returns False in case of error. @@ -1383,7 +1380,7 @@ Bool read_from_gdb_write_to_pid(int to_pid) return write_buf(to_pid, buf, nrread, "to_pid", /* notify */ True); } -static const int to_gdb = 1; +static int to_gdb = 1; /* stdout by default, changed if --port is given. */ static char *to_gdb_from_pid; /* fifo name to read pid replies */ /* Returns True in case read/write operations were done properly. Returns False in case of error. @@ -1407,6 +1404,44 @@ Bool read_from_pid_write_to_gdb(int from_pid) return write_buf(to_gdb, buf, nrread, "to_gdb", /* notify */ False); } +static +void wait_for_gdb_connect (int in_port) +{ + struct sockaddr_in addr; + + int listen_gdb = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + int gdb_connect; + + if (-1 == listen_gdb) { + XERROR(errno, "cannot create socket"); + } + + memset(&addr, 0, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_port = htons((unsigned short int)in_port); + addr.sin_addr.s_addr = INADDR_ANY; + + if (-1 == bind(listen_gdb,(struct sockaddr *)&addr, sizeof(addr))) { + XERROR(errno, "bind failed"); + } + fprintf(stderr, "listening on port %d ...", in_port); + fflush(stderr); + if (-1 == listen(listen_gdb, 1)) { + XERROR(errno, "error listen failed"); + } + + gdb_connect = accept(listen_gdb, NULL, NULL); + if (gdb_connect < 0) { + XERROR(errno, "accept failed"); + } + fprintf(stderr, "connected.\n"); + fflush(stderr); + close(listen_gdb); + from_gdb = gdb_connect; + to_gdb = gdb_connect; +} + /* prepares the FIFOs filenames, map the shared memory. */ static void prepare_fifos_and_shared_mem(int pid) @@ -1584,12 +1619,19 @@ void received_signal (int signum) sigpipe++; } else if (signum == SIGALRM) { sigalrm++; - DEBUG(1, "pthread_cancel invoke_gdbserver_in_valgrind_thread\n"); +#if defined(VGPV_arm_linux_android) + /* Android has no pthread_cancel. As it also does not have + PTRACE_INVOKER, there is no need for cleanup action. + So, we just do nothing. */ + DEBUG(1, "sigalrm received, no action on android\n"); +#else /* Note: we cannot directly invoke restore_and_detach : this must be done by the thread that has attached. We have in this thread pushed a cleanup handler that will cleanup what is needed. */ + DEBUG(1, "pthread_cancel invoke_gdbserver_in_valgrind_thread\n"); pthread_cancel(invoke_gdbserver_in_valgrind_thread); +#endif } else { ERROR(0, "unexpected signal %d\n", signum); } @@ -2008,6 +2050,7 @@ void usage(void) "\n" " OPTIONS are [--pid=] [--vgdb-prefix=]\n" " [--wait=] [--max-invoke-ms=]\n" +" [--port=\n" " [--cmd-time-out=] [-l] [-D] [-d]\n" " \n" " --pid arg must be given if multiple Valgrind gdbservers are found.\n" @@ -2019,6 +2062,7 @@ void usage(void) " --max-invoke-ms (default 100) gives the nr of milli-seconds after which vgdb\n" " will force the invocation of the Valgrind gdbserver (if the Valgrind\n" " process is blocked in a system call).\n" +" --port instructs vgdb to listen for gdb on the specified port nr.\n" " --cmd-time-out (default 99999999) tells vgdb to exit if the found Valgrind\n" " gdbserver has not processed a command after number seconds\n" " -l arg tells to show the list of running Valgrind gdbserver and then exit.\n" @@ -2230,6 +2274,7 @@ void parse_options(int argc, char** argv, Bool *p_show_list, int *p_arg_pid, int *p_check_trials, + int *p_port, int *p_last_command, char *commands[]) { @@ -2238,6 +2283,7 @@ void parse_options(int argc, char** argv, int arg_pid = -1; int check_trials = 1; int last_command = -1; + int int_port = 0; int i; int arg_errors = 0; @@ -2278,6 +2324,11 @@ void parse_options(int argc, char** argv, fprintf (stderr, "invalid --cmd-time-out argument %s\n", argv[i]); arg_errors++; } + } else if (is_opt(argv[i], "--port=")) { + if (!numeric_val(argv[i], &int_port)) { + fprintf (stderr, "invalid --port argument %s\n", argv[i]); + arg_errors++; + } } else if (is_opt(argv[i], "--vgdb-prefix=")) { vgdb_prefix = argv[i] + 14; } else if (is_opt(argv[i], "-c")) { @@ -2315,6 +2366,7 @@ void parse_options(int argc, char** argv, if (isatty(0) && !show_shared_mem && !show_list + && int_port == 0 && last_command == -1) { arg_errors++; fprintf (stderr, @@ -2341,6 +2393,12 @@ void parse_options(int argc, char** argv, "Can't use both --pid and -l options\n"); } + if (int_port > 0 && last_command != -1) { + arg_errors++; + fprintf (stderr, + "Can't use --port to send commands\n"); + } + if (arg_errors > 0) { fprintf (stderr, "args error. Try `vgdb --help` for more information\n"); exit(1); @@ -2350,6 +2408,7 @@ void parse_options(int argc, char** argv, *p_show_list = show_list; *p_arg_pid = arg_pid; *p_check_trials = check_trials; + *p_port = int_port; *p_last_command = last_command; } @@ -2362,6 +2421,7 @@ int main(int argc, char** argv) Bool show_list; int arg_pid; int check_trials; + int in_port; int last_command; char *commands[argc]; // we will never have more commands than args. @@ -2370,6 +2430,7 @@ int main(int argc, char** argv) &show_list, &arg_pid, &check_trials, + &in_port, &last_command, commands); @@ -2384,6 +2445,9 @@ int main(int argc, char** argv) prepare_fifos_and_shared_mem(pid); + if (in_port > 0) + wait_for_gdb_connect(in_port); + if (show_shared_mem) { fprintf(stderr, "vgdb %d " @@ -2412,5 +2476,3 @@ int main(int argc, char** argv) free (commands[i]); return 0; } - -#endif /* !defined(VGPV_arm_linux_android) */ diff --git a/docs/xml/manual-core-adv.xml b/docs/xml/manual-core-adv.xml index 042c2c3d9e..0ef20d2e9f 100644 --- a/docs/xml/manual-core-adv.xml +++ b/docs/xml/manual-core-adv.xml @@ -482,6 +482,44 @@ description of GDB's functionality. + +Connecting to an Android gdbserver + When developping applications for Android, you will typically use +a development system (on which the Android NDK is installed) to compile your +application. An Android target system or emulator will be used to run +the application. +In this setup, Valgrind and vgdb will run on the Android system, +while GDB will run on the development system. GDB will connect +to the vgdb running on the Android system using the Android NDK +'adb forward' application. + + Example: on the Android system, execute the following: + + + + On the development system, execute the following commands: + +GDB will use a local tcp/ip connection to connect to the Android adb forwarder. +Adb will establish a relay connection between the host system and the Android +target system. Pay attention to use the GDB delivered in the +Android NDK system (typically, arm-linux-androideabi-gdb), as the host +GDB is probably not able to debug Android arm applications. +Note that the local port nr (used by GDB) must not necessarily be equal +to the port number used by vgdb: adb can forward tcp/ip between different +port numbers. + + + + Monitor command handling by the Valgrind gdbserver @@ -899,8 +937,9 @@ $5 = 36 Unblocking processes blocked in system calls is not - currently implemented on Mac OS X. So you cannot connect to or - interrupt a process blocked in a system call on Mac OS X. + currently implemented on Mac OS X and Android. So you cannot + connect to or interrupt a process blocked in a system call on Mac + OS X or Android. @@ -1033,6 +1072,27 @@ options: The default value is to never time out. + + instructs vgdb to + use tcp/ip and listen for GDB on the specified port nr rather than + to use a pipe to communicate with GDB. Using tcp/ip allows to have + GDB running on one computer and debugging a Valgrind process + running on another target computer. + Example: + + On the computer which hosts GDB, execute the command: + + where targetip is the ip address or hostname of the target computer. + + To give more than one command to a