|  | /* | 
|  | * 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); | 
|  | } |