/*
 * Copyright 2006 The Android Open Source Project
 *
 * JDWP spy.
 */
#define _JDWP_MISC_INLINE
#include "Common.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.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 */
    uintptr_t offset;   /* offset to show while printing */
    char* hex;
    char* asc;
    int gap;

    if (mode == kHexDumpLocal)
        offset = 0;
    else
        offset = (uintptr_t) 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);
}