Example #1
0
void AtomSTTS::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) {
  uint32_t start=GETAVAILABLEBYTESCOUNT(data);
  VersionedAtom::SerializeToBuffer(data, maxFrames);
  _offset=GETAVAILABLEBYTESCOUNT(data);
  data.ReadFromDataType<uint32_t>(endianSwap32(_sttsEntries.size()));
  FOR_VECTOR(_sttsEntries, i) {
    data.ReadFromDataType<uint32_t>(endianSwap32(_sttsEntries[i].count));
    data.ReadFromDataType<uint32_t>(endianSwap32(_sttsEntries[i].delta));
  }
Example #2
0
/* FIXME-Recardo, remove parameters, and use document write method to write buffer */
void AtomSTSS::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) {
//  IOBuffer *data=reinterpret_cast<WriteMP4Document*>(_pDoc)->GetBuffer();
  uint32_t start=GETAVAILABLEBYTESCOUNT(data);

  VersionedAtom::SerializeToBuffer(data, maxFrames);
  _offset=GETAVAILABLEBYTESCOUNT(data);
  data.ReadFromDataType<uint32_t>(endianSwap32(_entries.size()));
  FOR_VECTOR(_entries, i) {
    data.ReadFromDataType<uint32_t>(endianSwap32(_entries[i]));
  }
Example #3
0
int loadHexFile(Core *core, const char *filename)
{
	FILE *file;
	char line[16];
	uint32_t *memptr = core->memory;

	file = fopen(filename, "r");
	if (file == NULL)
	{
		perror("Error opening hex memory file");
		return -1;
	}

	while (fgets(line, sizeof(line), file))
	{
		*memptr++ = endianSwap32(strtoul(line, NULL, 16));
		if ((size_t)((memptr - core->memory) * 4) >= core->memorySize)
		{
			fprintf(stderr, "hex file too bit to fit in memory\n");
			return -1;
		}
	}
	
	fclose(file);

	return 0;
}
Example #4
0
void AtomMDAT::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) {
  uint32_t start=GETAVAILABLEBYTESCOUNT(data);
  BaseAtom::SerializeToBuffer(data, maxFrames);

  _size=GETAVAILABLEBYTESCOUNT(data)-start;
  *(uint32_t*)(GETIBPOINTER(data)+start) = endianSwap32(_size);
}
Example #5
0
void AtomURL::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) {
  uint32_t start=GETAVAILABLEBYTESCOUNT(data);
  VersionedAtom::SerializeToBuffer(data, maxFrames);
  data.ReadFromString(_location);
  _size=GETAVAILABLEBYTESCOUNT(data)-start;
  *(uint32_t*)(GETIBPOINTER(data)+start) = endianSwap32(_size);
}
Example #6
0
/* ---------- PutCkEnd -------------------------------------------------*/
IFFP PutCkEnd(GroupContext *context0)
{
	register GroupContext *context = context0;
	WORD zero = 0;   /* padding source */

	if ( context->ckHdr.ckID == NULL_CHUNK )  /* not in a chunk */
		return(CLIENT_ERROR);

	if ( context->ckHdr.ckSize == szNotYetKnown ) {
		/* go back and set the chunk size to bytesSoFar */
		int offset = context->bytesSoFar+sizeof(int);
		if ( 0 > GSeek(context->file,
			-(offset),
			OFFSET_CURRENT))
		{
			return(DOS_ERROR);
		} else
		{
			context->bytesSoFar = endianSwap32(context->bytesSoFar);
			if (0 > fwrite(&context->bytesSoFar, 1,sizeof(int),context->file))
				return (DOS_ERROR);
			context->bytesSoFar = endianSwap32(context->bytesSoFar);
			if (0 > GSeek(context->file, context->bytesSoFar, OFFSET_CURRENT)  )
				return (DOS_ERROR);
		}


	}
	else {  /* make sure the client wrote as many bytes as planned */
		if ( context->ckHdr.ckSize != context->bytesSoFar )
			return(CLIENT_ERROR);
	};

	/* Write a pad byte if needed to bring us up to an even boundary.
	* Since the context end must be even, and since we haven't
	* overwritten the context, if we're on an odd position there must
	* be room for a pad byte. */
	if ( IS_ODD(context->bytesSoFar) ) {
		if ( 0 > fwrite(&zero, 1,1,context->file) )
			return(DOS_ERROR);
		context->position += 1;
	};

	context->ckHdr.ckID   = NULL_CHUNK;
	context->ckHdr.ckSize = context->bytesSoFar = 0;
	return(IFF_OKAY);
}
Example #7
0
/* ---------- PutCkHdr -------------------------------------------------*/
IFFP PutCkHdr(GroupContext *context0, int ckID, int ckSize)
{
	register GroupContext *context = context0;
	int minPSize = sizeof(ChunkHeader); /* physical chunk >= minPSize bytes*/

	/* CLIENT_ERROR if we're already inside a chunk or asked to write
	* other than one FORM, LIST, or CAT at the top level of a file */
	/* Also, non-positive int values are illegal and used for error codes.*/
	/* (We could check for other illegal IDs...)*/
	if ( context->ckHdr.ckID != NULL_CHUNK  ||  ckID <= 0 )
		return(CLIENT_ERROR);
	else if (context->parent == NULL)  {
		switch (ckID)  {
	   case FORM:  case LIST:  case CAT:  break;
	   default: return(CLIENT_ERROR);
		}
		if (context->position != 0)
			return(CLIENT_ERROR);
	}

	if ( Known(ckSize) ) {
		if ( ckSize < 0 )
			return(CLIENT_ERROR);
		minPSize += ckSize;
	};
	if ( Known(context->bound)  &&
		context->position + minPSize > context->bound )
		return(CLIENT_ERROR);

	context->ckHdr.ckID   = ckID;
	context->ckHdr.ckSize = ckSize;
	context->bytesSoFar   = 0;
	{
		context->ckHdr.ckSize = endianSwap32(context->ckHdr.ckSize);
		if (0 > fwrite(&context->ckHdr, 1,sizeof(ChunkHeader),context->file))
			return(DOS_ERROR);
		context->ckHdr.ckSize = endianSwap32(context->ckHdr.ckSize);
	}
	context->position += sizeof(ChunkHeader);
	return(IFF_OKAY);
}
Example #8
0
void AtomMVHD::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) {
  uint32_t start=GETAVAILABLEBYTESCOUNT(data);
  VersionedAtom::SerializeToBuffer(data, maxFrames);
  data.ReadFromDataType<uint32_t>(endianSwap32(_creationTime));
  data.ReadFromDataType<uint32_t>(endianSwap32(_modificationTime));
  data.ReadFromDataType<uint32_t>(endianSwap32(_timeScale));
  _offset=GETAVAILABLEBYTESCOUNT(data);
  data.ReadFromDataType<uint32_t>(endianSwap32(_duration));
  data.ReadFromDataType<uint32_t>(endianSwap32(_preferredRate));
  data.ReadFromDataType<uint16_t>(endianSwap16(_preferredVolume));
  data.ReadFromBuffer(_reserved, sizeof(_reserved));
  for (uint32_t i=0; i<9; i++) 
    data.ReadFromDataType<uint32_t>(endianSwap32(_matrixStructure[i]));
  for (uint32_t i=0; i<6; i++) {
    data.ReadFromRepeat(0x00, 4);
  }
  data.ReadFromDataType<uint32_t>(endianSwap32(_nextTrakId));
  _size=GETAVAILABLEBYTESCOUNT(data)-start;

  *(uint32_t*)(GETIBPOINTER(data)+start) = endianSwap32(_size);
}
Example #9
0
int parseHexVector(const char *str, uint32_t vectorValues[16], int endianSwap)
{
	const char *c = str;
	int lane;
	int digit;
	uint32_t laneValue;
	
	for (lane = 15; lane >= 0 && *c; lane--)
	{
		laneValue = 0;
		for (digit = 0; digit < 8; digit++)
		{
			if (*c >= '0' && *c <= '9')
				laneValue = (laneValue << 4) | (uint32_t) (*c - '0');
			else if (*c >= 'a' && *c <= 'f')
				laneValue = (laneValue << 4) | (uint32_t) (*c - 'a' + 10);
			else if (*c >= 'A' && *c <= 'F')
				laneValue = (laneValue << 4) | (uint32_t) (*c - 'A' + 10);
			else
			{
				printf("bad character %c in hex vector\n", *c);
				return 0;
			}

			if (*c == '\0')
			{
				printf("Error parsing hex vector\n");
				break;
			}
			else
				c++;
		}
		
		vectorValues[lane] = endianSwap ? endianSwap32(laneValue) : laneValue;
	}

	return 1;
}
Example #10
0
void remoteGdbMainLoop(Core *core, int enableFbWindow)
{
	int listenSocket;
	struct sockaddr_in address;
	socklen_t addressLength;
	int got;
	char request[256];
	uint32_t i;
	bool noAckMode = false;
	int optval;
	char response[256];
	uint32_t currentThread = 0;
	
	gCore = core;
	gLastSignals = calloc(sizeof(int), getTotalThreads(core));
	for (i = 0; i < getTotalThreads(core); i++)
		gLastSignals[i] = 0;

	listenSocket = socket(PF_INET, SOCK_STREAM, 0);
	if (listenSocket < 0)
	{
		perror("error setting up debug socket (socket)");
		return;
	}

	optval = 1;
	if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
	{
		perror("error setting up debug socket (setsockopt)");
		return;
	}
	
	address.sin_family = AF_INET;
	address.sin_port = htons(8000);
	address.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(listenSocket, (struct sockaddr*) &address, sizeof(address)) < 0)
	{	
		perror("error setting up debug socket (bind)");
		return;
	}

	if (listen(listenSocket, 1) < 0)
	{
		perror("error setting up debug socket (listen)");
		return;
	}
	
	while (true)
	{
		// Wait for a new client socket
		while (true)
		{
			addressLength = sizeof(address);
			gClientSocket = accept(listenSocket, (struct sockaddr*) &address,
				&addressLength);
			if (gClientSocket >= 0)
				break;
		}
		
		noAckMode = false;

		// Process commands
		while (true)
		{
			got = readPacket(request, sizeof(request));
			if (got < 0) 
				break;
			
			if (!noAckMode)
			{
				if (write(gClientSocket, "+", 1) != 1)
				{
					perror("Error writing to debug socket");
					exit(1);
				}
			}

			switch (request[0])
			{
				// Set arguments
				case 'A':
					// We don't support setting program arguments, so just silently ignore.
					sendResponsePacket("OK");
					break;

				// Continue
				case 'c':
				case 'C':
					runUntilInterrupt(core, ALL_THREADS, enableFbWindow);
					gLastSignals[currentThread] = TRAP_SIGNAL;
					sendFormattedResponse("S%02x", gLastSignals[currentThread]);
					break;

				// Pick thread
				case 'H':
					if (request[1] == 'g' || request[1] == 'c')
					{
						// XXX hack: the request type controls which operations this
						// applies for.
						currentThread = (uint32_t)(request[2] - '1');
						sendResponsePacket("OK");
					}
					else
						sendResponsePacket("");

					break;
					
				// Kill 
				case 'k':
					return;

				// Read/write memory
				case 'm':
				case 'M':
				{
					char *lenPtr;
					char *dataPtr;
					unsigned int start;
					unsigned int length;
					unsigned int offset;
					
					start = (uint32_t) strtoul(request + 1, &lenPtr, 16);
					length = (uint32_t) strtoul(lenPtr + 1, &dataPtr, 16);
					if (request[0] == 'm')
					{
						// Read memory
						for (offset = 0; offset < length; offset++)
							sprintf(response + offset * 2, "%02x", readMemoryByte(core, start + offset));
					
						sendResponsePacket(response);
					}
					else
					{
						// Write memory
						dataPtr += 1;	// Skip colon
						for (offset = 0; offset < length; offset++)
							writeMemoryByte(core, start + offset, decodeHexByte(dataPtr + offset * 2));

						sendResponsePacket("OK");
					}
					
					break;
				}

				// Read register
				case 'p':
				case 'g':
				{
					uint32_t regId = (uint32_t) strtoul(request + 1, NULL, 16);
					uint32_t value;
					if (regId < 32)
					{
						value = getScalarRegister(core, currentThread, regId);
						sendFormattedResponse("%08x", endianSwap32(value));
					}
					else if (regId < 64)
					{
						uint32_t lane;
						
						for (lane = 0; lane < NUM_VECTOR_LANES; lane++)
						{
							value = getVectorRegister(core, currentThread, regId, lane);
							sprintf(response + lane * 8, "%08x", endianSwap32(value));
						}

						sendResponsePacket(response);
					}
					else
						sendResponsePacket("");
				
					break;
				}
				
				// XXX need to implement write register
									
				// Query
				case 'q':
					if (strcmp(request + 1, "LaunchSuccess") == 0)
						sendResponsePacket("OK");
					else if (strcmp(request + 1, "HostInfo") == 0)
						sendResponsePacket("triple:nyuzi;endian:little;ptrsize:4");
					else if (strcmp(request + 1, "ProcessInfo") == 0)
						sendResponsePacket("pid:1");
					else if (strcmp(request + 1, "fThreadInfo") == 0)
						sendResponsePacket("m1,2,3,4");	// XXX need to query number of threads
					else if (strcmp(request + 1, "sThreadInfo") == 0)
						sendResponsePacket("l");
					else if (memcmp(request + 1, "ThreadStopInfo", 14) == 0)
						sprintf(response, "S%02x", gLastSignals[currentThread]);
					else if (memcmp(request + 1, "RegisterInfo", 12) == 0)
					{
						uint32_t regId = (uint32_t) strtoul(request + 13, NULL, 16);
						if (regId < 32)
						{
							sprintf(response, "name:s%d;bitsize:32;encoding:uint;format:hex;set:General Purpose Scalar Registers;gcc:%d;dwarf:%d;",
								regId, regId, regId);
								
							if (regId >= 28)
								sprintf(response + strlen(response), "generic:%s;", kGenericRegs[regId - 28]);
						}
						else if (regId < 64)
						{
							sprintf(response, "name:v%d;bitsize:512;encoding:uint;format:vector-uint32;set:General Purpose Vector Registers;gcc:%d;dwarf:%d;",
								regId - 32, regId, regId);
						}
						else
							strcpy(response, "");
						
						sendResponsePacket(response);
					}
					else if (strcmp(request + 1, "C") == 0)
						sendFormattedResponse("QC%02x", currentThread + 1);
					else
						sendResponsePacket("");	// Not supported
					
					break;

				// Set Value
				case 'Q':
					if (strcmp(request + 1, "StartNoAckMode") == 0)
					{
						noAckMode = true;
						sendResponsePacket("OK");
					}
					else
						sendResponsePacket("");	// Not supported
					
					break;
					
				// Single step
				case 's':
				case 'S':
					singleStep(core, currentThread);
					gLastSignals[currentThread] = TRAP_SIGNAL;
					sendFormattedResponse("S%02x", gLastSignals[currentThread]);
					break;
					
				// Multi-character command
				case 'v':
					if (strcmp(request, "vCont?") == 0)
						sendResponsePacket("vCont;C;c;S;s");
					else if (memcmp(request, "vCont;", 6) == 0)
					{
						// XXX hack.  There are two things lldb requests.  One is
						// to step one thread while resuming the others.  In this case,
						// I cheat and only step the one.  The other is just to continue,
						// which I perform in the else clause.
						const char *sreq = strchr(request, 's');
						if (sreq != NULL)
						{
							// s:0001
							currentThread = (uint32_t) strtoul(sreq + 2, NULL, 16) - 1;
							singleStep(core, currentThread);
							gLastSignals[currentThread] = TRAP_SIGNAL;
							sendFormattedResponse("S%02x", gLastSignals[currentThread]);
						}
						else
						{
							runUntilInterrupt(core, ALL_THREADS, enableFbWindow);
							gLastSignals[currentThread] = TRAP_SIGNAL;
							sendFormattedResponse("S%02x", gLastSignals[currentThread]);
						}
					}
					else
						sendResponsePacket("");
					
					break;
					
				// Clear breakpoint
				case 'z':
					if (clearBreakpoint(core, (uint32_t) strtoul(request + 3, NULL, 16)) < 0)
						sendResponsePacket(""); // Error
					else
						sendResponsePacket("OK");

					break;
					
				// Set breakpoint
				case 'Z':
					if (setBreakpoint(core, (uint32_t) strtoul(request + 3, NULL, 16)) < 0)
						sendResponsePacket(""); // Error
					else
						sendResponsePacket("OK");

					break;
					
				// Get last signal
				case '?':
					sprintf(response, "S%02x", gLastSignals[currentThread]);
					sendResponsePacket(response);
					break;
					
				// Unknown, return error
				default:
					sendResponsePacket("");
			}
		}

		close(gClientSocket);
	}
}
Example #11
0
int main(int argc, char ** argv)
{
  if(argc != 2)
  {
      printf("Usage is midiParse <file>\n");
      exit(1);
  }

  //now lets open it up
  FILE * mFile;
  mFile = fopen(argv[1], "r");
  if(!mFile)
    {
      //printf("Opening file \"%s\" failed. Aborting.\n", argv[1]);
      exit(1);
    }
    
    //get the file size
     // obtain file size:
     fseek (mFile , 0 , SEEK_END);
     uint32_t lSize = ftell(mFile);
     rewind (mFile);
     
     printf("Size = %d\n", lSize);

  //read the first header
  fread(&hChunk, 14, 1, mFile);

  /*printf("Header is [ ");
  printf("%s %08X %04X %04X %04X]\n",
	 &hChunk.type,
	 hChunk.length,
	 hChunk.format,
	 hChunk.numtrk,
	 hChunk.div
	 );*/
  //hChunk.type[4] = 0;
  //printf("Type is %s\n", &hChunk.type);
  //printf("Length is %d\n", endianSwap32(hChunk.length)); 
  //printf("Format is %d\n", endianSwap16(hChunk.format));
  //printf("Format is %d\n", endianSwap16(hChunk.numtrk));
  //printf("Format is %d\n", endianSwap16(hChunk.div));

  //TODO: allow for reading of any len > 5 headers
  if((endianSwap32(hChunk.length) != 6) || (endianSwap16(hChunk.format) == 2))
    {
      printf("Length of header corrupt or format unknown! Aborting.\n");
      exit(1);
    }

  fseek(mFile, 8 + endianSwap32(hChunk.length), SEEK_SET);
  
  //loop through the rest of the file
  while(ftell(mFile) < lSize)
    {
      char type[5];
      type[4] = 0;
      struct t_chunk * chunk = (struct t_chunk *)malloc(sizeof(struct t_chunk));
      printf("Reading chunk...\n");
      fread(&type, 1, 4, mFile);
      fread(&((*chunk).size), 4, 1, mFile);
      (*chunk).size = endianSwap32((*chunk).size);
      (*chunk).data = (uint8_t *)malloc((*chunk).size);
      fread((*chunk).data, 1, (*chunk).size, mFile);
      printf("Type %s, Length = %d bytes\n", type, (*chunk).size);
      //link them up
      if(TCs)
	{
	  //find the last one in the list
	  struct t_chunk * tmpTC = TCs;
	  while((*tmpTC).next)
	    {
	      tmpTC = (*tmpTC).next;
	      numTCs++;
	    }
	    //add our latest node
	    (*tmpTC).next = chunk;
	    numTCs++;
	}
      else
	{
	  TCs = chunk;
	  numTCs++;
	}
      //break;
      printf("at pos %d\n", ftell(mFile));
    }

  printf("Parsed %d Track Chunks.\n", numTCs);
  
  //parse events
  struct t_chunk * node = TCs;
  while(node)
    {
      parseEvents((*node).data, (*node).size);
      node = (*node).next;
    }
 
  return 0;
}
Example #12
0
void remoteGdbMainLoop(Core *core, int enableFbWindow)
{
	int listenSocket;
	struct sockaddr_in address;
	socklen_t addressLength;
	int got;
	char request[256];
	int i;
	int noAckMode = 0;
	int optval;
	char response[256];
	int currentThread = 0;
	
	gCore = core;
	gLastSignal = calloc(sizeof(int), getTotalThreads(core));
	for (i = 0; i < getTotalThreads(core); i++)
		gLastSignal[i] = 0;

	listenSocket = socket(PF_INET, SOCK_STREAM, 0);
	if (listenSocket < 0)
	{
		perror("socket");
		return;
	}

	optval = 1;
	setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
	
	address.sin_family = AF_INET;
	address.sin_port = htons(8000);
	address.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(listenSocket, (struct sockaddr*) &address, sizeof(address)) < 0)
	{	
		perror("bind");
		return;
	}

	if (listen(listenSocket, 4) < 0)
	{
		perror("bind");
		return;
	}
	
	while (1)
	{
		// Wait for a new client socket
		while (1)
		{
			addressLength = sizeof(address);
			gClientSocket = accept(listenSocket, (struct sockaddr*) &address,
				&addressLength);
			if (gClientSocket >= 0)
				break;
		}
		
#if DUMP_MESSAGES
		printf("Got connection from debugger\n");
#endif
		noAckMode = 0;

		// Process commands
		while (1)
		{
			got = readPacket(request, sizeof(request));
			if (got < 0) 
				break;
			
			if (!noAckMode)
				write(gClientSocket, "+", 1);

#if DUMP_MESSAGES
			printf("<< %s\n", request);
#endif

			switch (request[0])
			{
				// Set arguments
				case 'A':
					sendResponsePacket("OK");	// Yeah, whatever
					break;

				// continue
				case 'c':
				case 'C':
					runUntilInterrupt(core, -1, enableFbWindow);
					gLastSignal[currentThread] = TRAP_SIGNAL;
					sendFormattedResponse("S%02x", gLastSignal[currentThread]);
					break;

				// Pick thread
				case 'H':
					if (request[1] == 'g' || request[1] == 'c')
					{
						// XXX hack: the request type controls which operations this
						// applies for.
						currentThread = request[2] - '1';
						sendResponsePacket("OK");
					}
					else
					{
#if DUMP_MESSAGES
						printf("Unhandled command %s\n", request);
#endif
						sendResponsePacket("");
					}

					break;
					
				// Kill 
				case 'k':
#if DUMP_MESSAGES
					printf("Exit requested\n");
#endif
					exit(1);
					break;

				// Read/write memory
				case 'm':
				case 'M':
				{
					char *lenPtr;
					unsigned int start;
					unsigned int length;
					unsigned int offset;
					
					start = strtoul(request + 1, &lenPtr, 16);
					length = strtoul(lenPtr + 1, NULL, 16);
					if (request[0] == 'm')
					{
						// Read memory
						for (offset = 0; offset < length; offset++)
							sprintf(response + offset * 2, "%02x", readMemoryByte(core, start + offset));
					
						sendResponsePacket(response);
					}
					else
					{
						// XXX write memory
					}
					
					break;
				}

				// read register
				case 'p':
				case 'g':
				{
					int regId = strtoul(request + 1, NULL, 16);
					int value;
					if (regId < 32)
					{
						value = getScalarRegister(core, currentThread, regId);
						sendFormattedResponse("%08x", endianSwap32(value));
					}
					else if (regId < 64)
					{
						int lane;
						
						for (lane = 0; lane < 16; lane++)
						{
							value = getVectorRegister(core, currentThread, regId, lane);
							sprintf(response + lane * 8, "%08x", endianSwap32(value));
						}

						sendResponsePacket(response);
					}
					else
						sendResponsePacket("");
				
					break;
				}
									
				// Query
				case 'q':
					if (strcmp(request + 1, "LaunchSuccess") == 0)
						sendResponsePacket("OK");
					else if (strcmp(request + 1, "HostInfo") == 0)
						sendResponsePacket("triple:nyuzi;endian:little;ptrsize:4");
					else if (strcmp(request + 1, "ProcessInfo") == 0)
						sendResponsePacket("pid:1");
					else if (strcmp(request + 1, "fThreadInfo") == 0)
						sendResponsePacket("m1,2,3,4");
					else if (strcmp(request + 1, "sThreadInfo") == 0)
						sendResponsePacket("l");
					else if (memcmp(request + 1, "ThreadStopInfo", 14) == 0)
						sprintf(response, "S%02x", gLastSignal[currentThread]);
					else if (memcmp(request + 1, "RegisterInfo", 12) == 0)
					{
						int regId = strtoul(request + 13, NULL, 16);
						if (regId < 32)
						{
							sprintf(response, "name:s%d;bitsize:32;encoding:uint;format:hex;set:General Purpose Scalar Registers;gcc:%d;dwarf:%d;",
								regId, regId, regId);
								
							if (regId >= 28)
								sprintf(response + strlen(response), "generic:%s;", kGenericRegs[regId - 28]);
						}
						else if (regId < 64)
						{
							sprintf(response, "name:v%d;bitsize:512;encoding:uint;format:vector-uint32;set:General Purpose Vector Registers;gcc:%d;dwarf:%d;",
								regId - 32, regId, regId);
						}
						else
							strcpy(response, "");
						
						sendResponsePacket(response);
					}
					else if (strcmp(request + 1, "C") == 0)
						sendFormattedResponse("QC%02x", currentThread + 1);
					else
						sendResponsePacket("");	// Not supported
					
					break;

				// Set Value
				case 'Q':
					if (strcmp(request + 1, "StartNoAckMode") == 0)
					{
						noAckMode = 1;
						sendResponsePacket("OK");
					}
					else
						sendResponsePacket("");	// Not supported
					
					break;
					
				// Step
				case 's':
				case 'S':
					singleStep(core, currentThread);
					gLastSignal[currentThread] = TRAP_SIGNAL;
					sendFormattedResponse("S%02x", gLastSignal[currentThread]);
					break;
					
				// Multi-character command
				case 'v':
					if (strcmp(request, "vCont?") == 0)
						sendResponsePacket("vCont;C;c;S;s");
					else if (memcmp(request, "vCont;", 6) == 0)
					{
						// XXX hack.  There are two things lldb requests.  One is
						// to step one thread while resuming the others.  In this case,
						// I cheat and only step the one.  The other is just to continue,
						// which I perform in the else clause.
						const char *sreq = strchr(request, 's');
						if (sreq != NULL)
						{
							// s:0001
							currentThread = strtoul(sreq + 2, NULL, 16) - 1;
							singleStep(core, currentThread);
							gLastSignal[currentThread] = TRAP_SIGNAL;
							sendFormattedResponse("S%02x", gLastSignal[currentThread]);
						}
						else
						{
							runUntilInterrupt(core, -1, enableFbWindow);
							gLastSignal[currentThread] = TRAP_SIGNAL;
							sendFormattedResponse("S%02x", gLastSignal[currentThread]);
						}
					}
					else
						sendResponsePacket("");
					
					break;
					
				// Clear breakpoint
				case 'z':
					clearBreakpoint(core, strtoul(request + 3, NULL, 16));
					sendResponsePacket("OK");
					break;
					
				// Set breakpoint
				case 'Z':
					setBreakpoint(core, strtoul(request + 3, NULL, 16));
					sendResponsePacket("OK");
					break;
					
				// Get last signal
				case '?':
					sprintf(response, "S%02x", gLastSignal[currentThread]);
					sendResponsePacket(response);
					break;
					
				// Unknown
				default:
					sendResponsePacket("");
			}
		}
		
#if DUMP_MESSAGES
		printf("Disconnected from debugger\n");
#endif
		close(gClientSocket);
	}
}