diff options
author | 2014-01-30 16:26:34 -0800 | |
---|---|---|
committer | 2014-01-31 08:25:52 -0800 | |
commit | 2492b9ddb8111c7efbe7eb9e0c5c709c8878d0f2 (patch) | |
tree | dfb3df6a07052303f9ba3c9be829a081686888a0 | |
parent | 1cbed454da5d7760d7bc607ac164241e82a2b15e (diff) |
Remove jdwpspy.
Change-Id: Ic9814dadcf1ccf46e280bddde0dffbef8438e48d
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | jdwpspy/Android.mk | 25 | ||||
-rw-r--r-- | jdwpspy/Common.h | 98 | ||||
-rw-r--r-- | jdwpspy/Main.cpp | 139 | ||||
-rw-r--r-- | jdwpspy/Net.cpp | 751 |
5 files changed, 0 insertions, 1014 deletions
diff --git a/Android.mk b/Android.mk index 5ecbea3ec6..2c75accc9d 100644 --- a/Android.mk +++ b/Android.mk @@ -92,7 +92,6 @@ include $(art_path)/dex2oat/Android.mk include $(art_path)/disassembler/Android.mk include $(art_path)/oatdump/Android.mk include $(art_path)/dalvikvm/Android.mk -include $(art_path)/jdwpspy/Android.mk include $(art_build_path)/Android.oat.mk # ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES diff --git a/jdwpspy/Android.mk b/jdwpspy/Android.mk deleted file mode 100644 index 97162f0b0d..0000000000 --- a/jdwpspy/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (C) 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 -# -# 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. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= Main.cpp Net.cpp -LOCAL_C_INCLUDES += art/runtime -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk -LOCAL_MODULE := jdwpspy -include $(BUILD_HOST_EXECUTABLE) -ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE) diff --git a/jdwpspy/Common.h b/jdwpspy/Common.h deleted file mode 100644 index 30a49fba76..0000000000 --- a/jdwpspy/Common.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * jdwpspy common stuff. - */ -#ifndef ART_JDWPSPY_COMMON_H_ -#define ART_JDWPSPY_COMMON_H_ - -#include <stdint.h> -#include <stdio.h> -#include <sys/types.h> - -typedef uint8_t u1; -typedef uint16_t u2; -typedef uint32_t u4; -typedef uint64_t u8; - -#define NELEM(x) (sizeof(x) / sizeof((x)[0])) - -#ifndef _JDWP_MISC_INLINE -# define INLINE extern inline -#else -# define INLINE -#endif - -/* - * Get 1 byte. (Included to make the code more legible.) - */ -INLINE u1 get1(unsigned const char* pSrc) { - return *pSrc; -} - -/* - * Get 2 big-endian bytes. - */ -INLINE u2 get2BE(unsigned char const* pSrc) { - u2 result; - - result = *pSrc++ << 8; - result |= *pSrc++; - - return result; -} - -/* - * Get 4 big-endian bytes. - */ -INLINE u4 get4BE(unsigned char const* pSrc) { - u4 result; - - result = *pSrc++ << 24; - result |= *pSrc++ << 16; - result |= *pSrc++ << 8; - result |= *pSrc++; - - return result; -} - -/* - * Get 8 big-endian bytes. - */ -INLINE u8 get8BE(unsigned char const* pSrc) { - u8 result; - - result = (u8) *pSrc++ << 56; - result |= (u8) *pSrc++ << 48; - result |= (u8) *pSrc++ << 40; - result |= (u8) *pSrc++ << 32; - result |= (u8) *pSrc++ << 24; - result |= (u8) *pSrc++ << 16; - result |= (u8) *pSrc++ << 8; - result |= (u8) *pSrc++; - - return result; -} - - -/* - * Start here. - */ -int run(const char* connectHost, int connectPort, int listenPort); - -/* - * Print a hex dump to the specified file pointer. - * - * "local" mode prints a hex dump starting from offset 0 (roughly equivalent - * to "xxd -g1"). - * - * "mem" mode shows the actual memory address, and will offset the start - * so that the low nibble of the address is always zero. - */ -enum HexDumpMode { kHexDumpLocal, kHexDumpMem }; -void printHexDump(const void* vaddr, size_t length); -void printHexDump2(const void* vaddr, size_t length, const char* prefix); -void printHexDumpEx(FILE* fp, const void* vaddr, size_t length, - HexDumpMode mode, const char* prefix); - -#endif // ART_JDWPSPY_COMMON_H_ diff --git a/jdwpspy/Main.cpp b/jdwpspy/Main.cpp deleted file mode 100644 index 0f68d52c38..0000000000 --- a/jdwpspy/Main.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * JDWP spy. - */ -#define _JDWP_MISC_INLINE -#include "Common.h" -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <ctype.h> - -static const char gHexDigit[] = "0123456789abcdef"; - -/* - * Print a hex dump. Just hands control off to the fancy version. - */ -void printHexDump(const void* vaddr, size_t length) -{ - printHexDumpEx(stdout, vaddr, length, kHexDumpLocal, ""); -} -void printHexDump2(const void* vaddr, size_t length, const char* prefix) -{ - printHexDumpEx(stdout, vaddr, length, kHexDumpLocal, prefix); -} - -/* - * Print a hex dump in this format: - * -01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef\n - */ -void printHexDumpEx(FILE* fp, const void* vaddr, size_t length, - HexDumpMode mode, const char* prefix) -{ - const unsigned char* addr = reinterpret_cast<const unsigned char*>(vaddr); - char out[77]; /* exact fit */ - unsigned int offset; /* offset to show while printing */ - char* hex; - char* asc; - int gap; - - if (mode == kHexDumpLocal) - offset = 0; - else - offset = (int) addr; - - memset(out, ' ', sizeof(out)-1); - out[8] = ':'; - out[sizeof(out)-2] = '\n'; - out[sizeof(out)-1] = '\0'; - - gap = (int) offset & 0x0f; - while (length) { - unsigned int lineOffset = offset & ~0x0f; - char* hex = out; - char* asc = out + 59; - - for (int i = 0; i < 8; i++) { - *hex++ = gHexDigit[lineOffset >> 28]; - lineOffset <<= 4; - } - hex++; - hex++; - - int count = ((int)length > 16-gap) ? 16-gap : (int) length; /* cap length */ - assert(count != 0); - assert(count+gap <= 16); - - if (gap) { - /* only on first line */ - hex += gap * 3; - asc += gap; - } - - int i; - for (i = gap ; i < count+gap; i++) { - *hex++ = gHexDigit[*addr >> 4]; - *hex++ = gHexDigit[*addr & 0x0f]; - hex++; - if (isprint(*addr)) - *asc++ = *addr; - else - *asc++ = '.'; - addr++; - } - for ( ; i < 16; i++) { - /* erase extra stuff; only happens on last line */ - *hex++ = ' '; - *hex++ = ' '; - hex++; - *asc++ = ' '; - } - - fprintf(fp, "%s%s", prefix, out); - - gap = 0; - length -= count; - offset += count; - } -} - - -/* - * Explain it. - */ -static void usage(const char* progName) -{ - fprintf(stderr, "Usage: %s VM-port [debugger-listen-port]\n\n", progName); - fprintf(stderr, -"When a debugger connects to the debugger-listen-port, jdwpspy will connect\n"); - fprintf(stderr, "to the VM on the VM-port.\n"); -} - -/* - * Parse args. - */ -int main(int argc, char* argv[]) -{ - if (argc < 2 || argc > 3) { - usage("jdwpspy"); - return 2; - } - - setvbuf(stdout, NULL, _IONBF, 0); - - /* may want this to be host:port */ - int connectPort = atoi(argv[1]); - - int listenPort; - if (argc > 2) - listenPort = atoi(argv[2]); - else - listenPort = connectPort + 1; - - int cc = run("localhost", connectPort, listenPort); - - return (cc != 0); -} diff --git a/jdwpspy/Net.cpp b/jdwpspy/Net.cpp deleted file mode 100644 index 38d4e260af..0000000000 --- a/jdwpspy/Net.cpp +++ /dev/null @@ -1,751 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * JDWP spy. This is a rearranged version of the JDWP code from the VM. - */ -#include "Common.h" -#include "jdwp/jdwp_constants.h" - -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <time.h> -#include <errno.h> -#include <assert.h> - -#include <iostream> -#include <sstream> - -#define kInputBufferSize (256*1024) - -#define kMagicHandshakeLen 14 /* "JDWP-Handshake" */ -#define kJDWPHeaderLen 11 -#define kJDWPFlagReply 0x80 - - -/* - * Information about the remote end. - */ -struct Peer { - char label[2]; /* 'D' or 'V' */ - - int sock; - unsigned char inputBuffer[kInputBufferSize]; - int inputCount; - - bool awaitingHandshake; /* waiting for "JDWP-Handshake" */ -}; - - -/* - * Network state. - */ -struct NetState { - /* listen here for connection from debugger */ - int listenSock; - - /* connect here to contact VM */ - in_addr vmAddr; - uint16_t vmPort; - - Peer dbg; - Peer vm; -}; - -/* - * Function names. - */ -struct JdwpHandlerMap { - u1 cmdSet; - u1 cmd; - const char* descr; -}; - -/* - * Map commands to names. - * - * Command sets 0-63 are incoming requests, 64-127 are outbound requests, - * and 128-256 are vendor-defined. - */ -static const JdwpHandlerMap gHandlerMap[] = { - /* VirtualMachine command set (1) */ - { 1, 1, "VirtualMachine.Version" }, - { 1, 2, "VirtualMachine.ClassesBySignature" }, - { 1, 3, "VirtualMachine.AllClasses" }, - { 1, 4, "VirtualMachine.AllThreads" }, - { 1, 5, "VirtualMachine.TopLevelThreadGroups" }, - { 1, 6, "VirtualMachine.Dispose" }, - { 1, 7, "VirtualMachine.IDSizes" }, - { 1, 8, "VirtualMachine.Suspend" }, - { 1, 9, "VirtualMachine.Resume" }, - { 1, 10, "VirtualMachine.Exit" }, - { 1, 11, "VirtualMachine.CreateString" }, - { 1, 12, "VirtualMachine.Capabilities" }, - { 1, 13, "VirtualMachine.ClassPaths" }, - { 1, 14, "VirtualMachine.DisposeObjects" }, - { 1, 15, "VirtualMachine.HoldEvents" }, - { 1, 16, "VirtualMachine.ReleaseEvents" }, - { 1, 17, "VirtualMachine.CapabilitiesNew" }, - { 1, 18, "VirtualMachine.RedefineClasses" }, - { 1, 19, "VirtualMachine.SetDefaultStratum" }, - { 1, 20, "VirtualMachine.AllClassesWithGeneric"}, - { 1, 21, "VirtualMachine.InstanceCounts"}, - - /* ReferenceType command set (2) */ - { 2, 1, "ReferenceType.Signature" }, - { 2, 2, "ReferenceType.ClassLoader" }, - { 2, 3, "ReferenceType.Modifiers" }, - { 2, 4, "ReferenceType.Fields" }, - { 2, 5, "ReferenceType.Methods" }, - { 2, 6, "ReferenceType.GetValues" }, - { 2, 7, "ReferenceType.SourceFile" }, - { 2, 8, "ReferenceType.NestedTypes" }, - { 2, 9, "ReferenceType.Status" }, - { 2, 10, "ReferenceType.Interfaces" }, - { 2, 11, "ReferenceType.ClassObject" }, - { 2, 12, "ReferenceType.SourceDebugExtension" }, - { 2, 13, "ReferenceType.SignatureWithGeneric" }, - { 2, 14, "ReferenceType.FieldsWithGeneric" }, - { 2, 15, "ReferenceType.MethodsWithGeneric" }, - { 2, 16, "ReferenceType.Instances" }, - { 2, 17, "ReferenceType.ClassFileVersion" }, - { 2, 18, "ReferenceType.ConstantPool" }, - - /* ClassType command set (3) */ - { 3, 1, "ClassType.Superclass" }, - { 3, 2, "ClassType.SetValues" }, - { 3, 3, "ClassType.InvokeMethod" }, - { 3, 4, "ClassType.NewInstance" }, - - /* ArrayType command set (4) */ - { 4, 1, "ArrayType.NewInstance" }, - - /* InterfaceType command set (5) */ - - /* Method command set (6) */ - { 6, 1, "Method.LineTable" }, - { 6, 2, "Method.VariableTable" }, - { 6, 3, "Method.Bytecodes" }, - { 6, 4, "Method.IsObsolete" }, - { 6, 5, "Method.VariableTableWithGeneric" }, - - /* Field command set (8) */ - - /* ObjectReference command set (9) */ - { 9, 1, "ObjectReference.ReferenceType" }, - { 9, 2, "ObjectReference.GetValues" }, - { 9, 3, "ObjectReference.SetValues" }, - { 9, 4, "ObjectReference.UNUSED" }, - { 9, 5, "ObjectReference.MonitorInfo" }, - { 9, 6, "ObjectReference.InvokeMethod" }, - { 9, 7, "ObjectReference.DisableCollection" }, - { 9, 8, "ObjectReference.EnableCollection" }, - { 9, 9, "ObjectReference.IsCollected" }, - { 9, 10, "ObjectReference.ReferringObjects" }, - - /* StringReference command set (10) */ - { 10, 1, "StringReference.Value" }, - - /* ThreadReference command set (11) */ - { 11, 1, "ThreadReference.Name" }, - { 11, 2, "ThreadReference.Suspend" }, - { 11, 3, "ThreadReference.Resume" }, - { 11, 4, "ThreadReference.Status" }, - { 11, 5, "ThreadReference.ThreadGroup" }, - { 11, 6, "ThreadReference.Frames" }, - { 11, 7, "ThreadReference.FrameCount" }, - { 11, 8, "ThreadReference.OwnedMonitors" }, - { 11, 9, "ThreadReference.CurrentContendedMonitor" }, - { 11, 10, "ThreadReference.Stop" }, - { 11, 11, "ThreadReference.Interrupt" }, - { 11, 12, "ThreadReference.SuspendCount" }, - { 11, 13, "ThreadReference.OwnedMonitorsStackDepthInfo" }, - { 11, 14, "ThreadReference.ForceEarlyReturn" }, - - /* ThreadGroupReference command set (12) */ - { 12, 1, "ThreadGroupReference.Name" }, - { 12, 2, "ThreadGroupReference.Parent" }, - { 12, 3, "ThreadGroupReference.Children" }, - - /* ArrayReference command set (13) */ - { 13, 1, "ArrayReference.Length" }, - { 13, 2, "ArrayReference.GetValues" }, - { 13, 3, "ArrayReference.SetValues" }, - - /* ClassLoaderReference command set (14) */ - { 14, 1, "ArrayReference.VisibleClasses" }, - - /* EventRequest command set (15) */ - { 15, 1, "EventRequest.Set" }, - { 15, 2, "EventRequest.Clear" }, - { 15, 3, "EventRequest.ClearAllBreakpoints" }, - - /* StackFrame command set (16) */ - { 16, 1, "StackFrame.GetValues" }, - { 16, 2, "StackFrame.SetValues" }, - { 16, 3, "StackFrame.ThisObject" }, - { 16, 4, "StackFrame.PopFrames" }, - - /* ClassObjectReference command set (17) */ - { 17, 1, "ClassObjectReference.ReflectedType" }, - - /* Event command set (64) */ - { 64, 100, "Event.Composite" }, - - /* DDMS */ - { 199, 1, "DDMS.Chunk" }, -}; - -/* - * Look up a command's name. - */ -static const char* getCommandName(int cmdSet, int cmd) -{ - for (int i = 0; i < (int) NELEM(gHandlerMap); i++) { - if (gHandlerMap[i].cmdSet == cmdSet && - gHandlerMap[i].cmd == cmd) - { - return gHandlerMap[i].descr; - } - } - - return "?UNKNOWN?"; -} - - -void jdwpNetFree(NetState* netState); /* fwd */ - -/* - * Allocate state structure and bind to the listen port. - * - * Returns 0 on success. - */ -NetState* jdwpNetStartup(uint16_t listenPort, const char* connectHost, uint16_t connectPort) { - NetState* netState = new NetState; - memset(netState, 0, sizeof(*netState)); - netState->listenSock = -1; - netState->dbg.sock = netState->vm.sock = -1; - - strcpy(netState->dbg.label, "D"); - strcpy(netState->vm.label, "V"); - - /* - * Set up a socket to listen for connections from the debugger. - */ - - netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (netState->listenSock < 0) { - fprintf(stderr, "Socket create failed: %s\n", strerror(errno)); - goto fail; - } - - /* allow immediate re-use if we die */ - { - int one = 1; - if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one, - sizeof(one)) < 0) - { - fprintf(stderr, "setsockopt(SO_REUSEADDR) failed: %s\n", - strerror(errno)); - goto fail; - } - } - - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(listenPort); - addr.sin_addr.s_addr = INADDR_ANY; - - if (bind(netState->listenSock, (sockaddr*) &addr, sizeof(addr)) != 0) - { - fprintf(stderr, "attempt to bind to port %u failed: %s\n", - listenPort, strerror(errno)); - goto fail; - } - - fprintf(stderr, "+++ bound to port %u\n", listenPort); - - if (listen(netState->listenSock, 5) != 0) { - fprintf(stderr, "Listen failed: %s\n", strerror(errno)); - goto fail; - } - - /* - * Do the hostname lookup for the VM. - */ - hostent* pHost; - - pHost = gethostbyname(connectHost); - if (pHost == NULL) { - fprintf(stderr, "Name lookup of '%s' failed: %s\n", - connectHost, strerror(h_errno)); - goto fail; - } - - netState->vmAddr = *((in_addr*) pHost->h_addr_list[0]); - netState->vmPort = connectPort; - - fprintf(stderr, "+++ connect host resolved to %s\n", - inet_ntoa(netState->vmAddr)); - - return netState; - -fail: - jdwpNetFree(netState); - return NULL; -} - -/* - * Shut down JDWP listener. Don't free state. - * - * Note that "netState" may be partially initialized if "startup" failed. - */ -void jdwpNetShutdown(NetState* netState) -{ - int listenSock = netState->listenSock; - int dbgSock = netState->dbg.sock; - int vmSock = netState->vm.sock; - - /* clear these out so it doesn't wake up and try to reuse them */ - /* (important when multi-threaded) */ - netState->listenSock = netState->dbg.sock = netState->vm.sock = -1; - - if (listenSock >= 0) { - shutdown(listenSock, SHUT_RDWR); - close(listenSock); - } - if (dbgSock >= 0) { - shutdown(dbgSock, SHUT_RDWR); - close(dbgSock); - } - if (vmSock >= 0) { - shutdown(vmSock, SHUT_RDWR); - close(vmSock); - } -} - -/* - * Shut down JDWP listener and free its state. - */ -void jdwpNetFree(NetState* netState) -{ - if (netState == NULL) - return; - - jdwpNetShutdown(netState); - delete netState; -} - -/* - * Disable the TCP Nagle algorithm, which delays transmission of outbound - * packets until the previous transmissions have been acked. JDWP does a - * lot of back-and-forth with small packets, so this may help. - */ -static int setNoDelay(int fd) -{ - int cc, on = 1; - - cc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - assert(cc == 0); - return cc; -} - -/* - * Accept a connection. This will block waiting for somebody to show up. - */ -bool jdwpAcceptConnection(NetState* netState) -{ - sockaddr_in addr; - socklen_t addrlen; - int sock; - - if (netState->listenSock < 0) - return false; /* you're not listening! */ - - assert(netState->dbg.sock < 0); /* must not already be talking */ - - addrlen = sizeof(addr); - do { - sock = accept(netState->listenSock, (sockaddr*) &addr, &addrlen); - if (sock < 0 && errno != EINTR) { - fprintf(stderr, "accept failed: %s\n", strerror(errno)); - return false; - } - } while (sock < 0); - - fprintf(stderr, "+++ accepted connection from %s:%u\n", - inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - - netState->dbg.sock = sock; - netState->dbg.awaitingHandshake = true; - netState->dbg.inputCount = 0; - - setNoDelay(sock); - - return true; -} - -/* - * Close the connections to the debugger and VM. - * - * Reset the state so we're ready to receive a new connection. - */ -void jdwpCloseConnection(NetState* netState) -{ - if (netState->dbg.sock >= 0) { - fprintf(stderr, "+++ closing connection to debugger\n"); - close(netState->dbg.sock); - netState->dbg.sock = -1; - } - if (netState->vm.sock >= 0) { - fprintf(stderr, "+++ closing connection to vm\n"); - close(netState->vm.sock); - netState->vm.sock = -1; - } -} - -/* - * Figure out if we have a full packet in the buffer. - */ -static bool haveFullPacket(Peer* pPeer) -{ - long length; - - if (pPeer->awaitingHandshake) - return (pPeer->inputCount >= kMagicHandshakeLen); - - if (pPeer->inputCount < 4) - return false; - - length = get4BE(pPeer->inputBuffer); - return (pPeer->inputCount >= length); -} - -/* - * Consume bytes from the buffer. - * - * This would be more efficient with a circular buffer. However, we're - * usually only going to find one packet, which is trivial to handle. - */ -static void consumeBytes(Peer* pPeer, int count) -{ - assert(count > 0); - assert(count <= pPeer->inputCount); - - if (count == pPeer->inputCount) { - pPeer->inputCount = 0; - return; - } - - memmove(pPeer->inputBuffer, pPeer->inputBuffer + count, - pPeer->inputCount - count); - pPeer->inputCount -= count; -} - -/* - * Get the current time. - */ -static void getCurrentTime(int* pMin, int* pSec) -{ - time_t now; - tm* ptm; - - now = time(NULL); - ptm = localtime(&now); - *pMin = ptm->tm_min; - *pSec = ptm->tm_sec; -} - -/* - * Dump the contents of a packet to stdout. - */ -static void dumpPacket(const unsigned char* packetBuf, const char* srcName, - const char* dstName) -{ - const unsigned char* buf = packetBuf; - char prefix[3]; - u4 length, id; - u1 flags, cmdSet=0, cmd=0; - art::JDWP::JdwpError error = art::JDWP::ERR_NONE; - bool reply; - int dataLen; - - length = get4BE(buf+0); - id = get4BE(buf+4); - flags = get1(buf+8); - if ((flags & kJDWPFlagReply) != 0) { - reply = true; - error = static_cast<art::JDWP::JdwpError>(get2BE(buf+9)); - } else { - reply = false; - cmdSet = get1(buf+9); - cmd = get1(buf+10); - } - - buf += kJDWPHeaderLen; - dataLen = length - (buf - packetBuf); - - if (!reply) { - prefix[0] = srcName[0]; - prefix[1] = '>'; - } else { - prefix[0] = dstName[0]; - prefix[1] = '<'; - } - prefix[2] = '\0'; - - int min, sec; - getCurrentTime(&min, &sec); - - if (!reply) { - printf("%s REQUEST dataLen=%-5u id=0x%08x flags=0x%02x cmd=%d/%d [%02d:%02d]\n", - prefix, dataLen, id, flags, cmdSet, cmd, min, sec); - printf("%s --> %s\n", prefix, getCommandName(cmdSet, cmd)); - } else { - std::ostringstream ss; - ss << "TODO"; // get access to the operator<<, or regenerate it for jdwpspy? - printf("%s REPLY dataLen=%-5u id=0x%08x flags=0x%02x err=%d (%s) [%02d:%02d]\n", - prefix, dataLen, id, flags, error, ss.str().c_str(), min,sec); - } - if (dataLen > 0) - printHexDump2(buf, dataLen, prefix); - printf("%s ----------\n", prefix); -} - -/* - * Handle a packet. Returns "false" if we encounter a connection-fatal error. - */ -static bool handlePacket(Peer* pDst, Peer* pSrc) -{ - const unsigned char* buf = pSrc->inputBuffer; - u4 length; - u1 flags; - int cc; - - length = get4BE(buf+0); - flags = get1(buf+9); - - assert((int) length <= pSrc->inputCount); - - dumpPacket(buf, pSrc->label, pDst->label); - - cc = write(pDst->sock, buf, length); - if (cc != (int) length) { - fprintf(stderr, "Failed sending packet: %s\n", strerror(errno)); - return false; - } - /*printf("*** wrote %d bytes from %c to %c\n", - cc, pSrc->label[0], pDst->label[0]);*/ - - consumeBytes(pSrc, length); - return true; -} - -/* - * Handle incoming data. If we have a full packet in the buffer, process it. - */ -static bool handleIncoming(Peer* pWritePeer, Peer* pReadPeer) -{ - if (haveFullPacket(pReadPeer)) { - if (pReadPeer->awaitingHandshake) { - printf("Handshake [%c]: %.14s\n", - pReadPeer->label[0], pReadPeer->inputBuffer); - if (write(pWritePeer->sock, pReadPeer->inputBuffer, - kMagicHandshakeLen) != kMagicHandshakeLen) - { - fprintf(stderr, - "+++ [%c] handshake write failed\n", pReadPeer->label[0]); - goto fail; - } - consumeBytes(pReadPeer, kMagicHandshakeLen); - pReadPeer->awaitingHandshake = false; - } else { - if (!handlePacket(pWritePeer, pReadPeer)) - goto fail; - } - } else { - /*printf("*** %c not full yet\n", pReadPeer->label[0]);*/ - } - - return true; - -fail: - return false; -} - -/* - * Process incoming data. If no data is available, this will block until - * some arrives. - * - * Returns "false" on error (indicating that the connection has been severed). - */ -bool jdwpProcessIncoming(NetState* netState) -{ - int cc; - - assert(netState->dbg.sock >= 0); - assert(netState->vm.sock >= 0); - - while (!haveFullPacket(&netState->dbg) && !haveFullPacket(&netState->vm)) { - /* read some more */ - int highFd; - fd_set readfds; - - highFd = (netState->dbg.sock > netState->vm.sock) ? - netState->dbg.sock+1 : netState->vm.sock+1; - FD_ZERO(&readfds); - FD_SET(netState->dbg.sock, &readfds); - FD_SET(netState->vm.sock, &readfds); - - errno = 0; - cc = select(highFd, &readfds, NULL, NULL, NULL); - if (cc < 0) { - if (errno == EINTR) { - fprintf(stderr, "+++ EINTR on select\n"); - continue; - } - fprintf(stderr, "+++ select failed: %s\n", strerror(errno)); - goto fail; - } - - if (FD_ISSET(netState->dbg.sock, &readfds)) { - cc = read(netState->dbg.sock, - netState->dbg.inputBuffer + netState->dbg.inputCount, - sizeof(netState->dbg.inputBuffer) - netState->dbg.inputCount); - if (cc < 0) { - if (errno == EINTR) { - fprintf(stderr, "+++ EINTR on read\n"); - continue; - } - fprintf(stderr, "+++ dbg read failed: %s\n", strerror(errno)); - goto fail; - } - if (cc == 0) { - if (sizeof(netState->dbg.inputBuffer) == - netState->dbg.inputCount) - fprintf(stderr, "+++ debugger sent huge message\n"); - else - fprintf(stderr, "+++ debugger disconnected\n"); - goto fail; - } - - /*printf("*** %d bytes from dbg\n", cc);*/ - netState->dbg.inputCount += cc; - } - - if (FD_ISSET(netState->vm.sock, &readfds)) { - cc = read(netState->vm.sock, - netState->vm.inputBuffer + netState->vm.inputCount, - sizeof(netState->vm.inputBuffer) - netState->vm.inputCount); - if (cc < 0) { - if (errno == EINTR) { - fprintf(stderr, "+++ EINTR on read\n"); - continue; - } - fprintf(stderr, "+++ vm read failed: %s\n", strerror(errno)); - goto fail; - } - if (cc == 0) { - if (sizeof(netState->vm.inputBuffer) == - netState->vm.inputCount) - fprintf(stderr, "+++ vm sent huge message\n"); - else - fprintf(stderr, "+++ vm disconnected\n"); - goto fail; - } - - /*printf("*** %d bytes from vm\n", cc);*/ - netState->vm.inputCount += cc; - } - } - - if (!handleIncoming(&netState->dbg, &netState->vm)) - goto fail; - if (!handleIncoming(&netState->vm, &netState->dbg)) - goto fail; - - return true; - -fail: - jdwpCloseConnection(netState); - return false; -} - -/* - * Connect to the VM. - */ -bool jdwpConnectToVm(NetState* netState) -{ - sockaddr_in addr; - int sock = -1; - - sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) { - fprintf(stderr, "Socket create failed: %s\n", strerror(errno)); - goto fail; - } - - addr.sin_family = AF_INET; - addr.sin_addr = netState->vmAddr; - addr.sin_port = htons(netState->vmPort); - if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) { - fprintf(stderr, "Connection to %s:%u failed: %s\n", - inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), strerror(errno)); - goto fail; - } - fprintf(stderr, "+++ connected to VM %s:%u\n", - inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - - netState->vm.sock = sock; - netState->vm.awaitingHandshake = true; - netState->vm.inputCount = 0; - - setNoDelay(netState->vm.sock); - return true; - -fail: - if (sock >= 0) - close(sock); - return false; -} - -/* - * Establish network connections and start things running. - * - * We wait for a new connection from the debugger. When one arrives we - * open a connection to the VM. If one side or the other goes away, we - * drop both ends and go back to listening. - */ -int run(const char* connectHost, int connectPort, int listenPort) -{ - NetState* state; - - state = jdwpNetStartup(listenPort, connectHost, connectPort); - if (state == NULL) - return -1; - - while (true) { - if (!jdwpAcceptConnection(state)) - break; - - if (jdwpConnectToVm(state)) { - while (true) { - if (!jdwpProcessIncoming(state)) - break; - } - } - - jdwpCloseConnection(state); - } - - jdwpNetFree(state); - - return 0; -} |