Esempio n. 1
0
// This one can load both leftover map files on game discs (like Zelda), and mapfiles
// produced by SaveSymbolMap below.
bool PPCSymbolDB::LoadMap(const std::string& filename)
{
	File::IOFile f(filename, "r");
	if (!f)
		return false;

	bool started = false;

	char line[512];
	while (fgets(line, 512, f.GetHandle()))
	{
		if (strlen(line) < 4)
			continue;

		char temp[256];
		sscanf(line, "%255s", temp);

		if (strcmp(temp, "UNUSED")==0) continue;
		if (strcmp(temp, ".text")==0)  {started = true; continue;};
		if (strcmp(temp, ".init")==0)  {started = true; continue;};
		if (strcmp(temp, "Starting")==0) continue;
		if (strcmp(temp, "extab")==0) continue;
		if (strcmp(temp, ".ctors")==0) break; //uh?
		if (strcmp(temp, ".dtors")==0) break;
		if (strcmp(temp, ".rodata")==0) continue;
		if (strcmp(temp, ".data")==0) continue;
		if (strcmp(temp, ".sbss")==0) continue;
		if (strcmp(temp, ".sdata")==0) continue;
		if (strcmp(temp, ".sdata2")==0) continue;
		if (strcmp(temp, "address")==0)  continue;
		if (strcmp(temp, "-----------------------")==0)  continue;
		if (strcmp(temp, ".sbss2")==0) break;
		if (temp[1] == ']') continue;

		if (!started) continue;

		u32 address, vaddress, size, unknown;
		char name[512];
		sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name);

		const char *namepos = strstr(line, name);
		if (namepos != nullptr) //would be odd if not :P
			strcpy(name, namepos);
		name[strlen(name) - 1] = 0;

		// we want the function names only .... TODO: or do we really? aren't we wasting information here?
		for (size_t i = 0; i < strlen(name); i++)
		{
			if (name[i] == ' ') name[i] = 0x00;
			if (name[i] == '(') name[i] = 0x00;
		}

		// Check if this is a valid entry.
		if (strcmp(name, ".text") != 0 || strcmp(name, ".init") != 0 || strlen(name) > 0)
		{
			AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION
		}
	}

	Index();
	return true;
}
Esempio n. 2
0
// This one can load both leftover map files on game discs (like Zelda), and mapfiles
// produced by SaveSymbolMap below.
// bad=true means carefully load map files that might not be from exactly the right version
bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad)
{
	File::IOFile f(filename, "r");
	if (!f)
		return false;

	// four columns are used in American Mensa Academy map files and perhaps other games
	bool started = false, four_columns = false;
	int good_count = 0, bad_count = 0;

	char line[512];
	while (fgets(line, 512, f.GetHandle()))
	{
		size_t length = strlen(line);
		if (length < 4)
			continue;

		if (length == 34 && strcmp(line, "  address  Size   address  offset\n") == 0)
		{
			four_columns = true;
			continue;
		}

		char temp[256];
		sscanf(line, "%255s", temp);

		if (strcmp(temp, "UNUSED")==0) continue;
		if (strcmp(temp, ".text")==0)  {started = true; continue;};
		if (strcmp(temp, ".init")==0)  {started = true; continue;};
		if (strcmp(temp, "Starting")==0) continue;
		if (strcmp(temp, "extab")==0) continue;
		if (strcmp(temp, ".ctors")==0) break; //uh?
		if (strcmp(temp, ".dtors")==0) break;
		if (strcmp(temp, ".rodata")==0) continue;
		if (strcmp(temp, ".data")==0) continue;
		if (strcmp(temp, ".sbss")==0) continue;
		if (strcmp(temp, ".sdata")==0) continue;
		if (strcmp(temp, ".sdata2")==0) continue;
		if (strcmp(temp, "address")==0)  continue;
		if (strcmp(temp, "-----------------------")==0)  continue;
		if (strcmp(temp, ".sbss2")==0) break;
		if (temp[1] == ']') continue;

		if (!started) continue;

		u32 address, vaddress, size, offset, unknown;
		char name[512], container[512];
		if (four_columns)
		{
			// sometimes there is no unknown number, and sometimes it is because it is an entry of something else
			if (length > 37 && line[37]==' ')
			{
				unknown = 0;
				sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name);
				char *s = strstr(line, "(entry of ");
				if (s)
				{
					sscanf(s + 10, "%511s", container);
					char *s2 = (strchr(container, ')'));
					if (s2 && container[0]!='.')
					{
						s2[0] = '\0';
						strcat(container, "::");
						strcat(container, name);
						strcpy(name, container);
					}
				}
			}
			else
			{
				sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset, &unknown, name);
			}
		}
		// some entries in the table have a function name followed by " (entry of " followed by a container name, followed by ")"
		// instead of a space followed by a number followed by a space followed by a name
		else if (length > 27 && line[27] != ' ' && strstr(line, "(entry of "))
		{
			unknown = 0;
			sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name);
			char *s = strstr(line, "(entry of ");
			if (s)
			{
				sscanf(s + 10, "%511s", container);
				char *s2 = (strchr(container, ')'));
				if (s2 && container[0] != '.')
				{
					s2[0] = '\0';
					strcat(container, "::");
					strcat(container, name);
					strcpy(name, container);
				}
			}
		}
		else
		{
			sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name);
		}

		const char *namepos = strstr(line, name);
		if (namepos != nullptr) //would be odd if not :P
			strcpy(name, namepos);
		name[strlen(name) - 1] = 0;

		// we want the function names only .... TODO: or do we really? aren't we wasting information here?
		for (size_t i = 0; i < strlen(name); i++)
		{
			if (name[i] == ' ') name[i] = 0x00;
			if (name[i] == '(') name[i] = 0x00;
		}

		// Check if this is a valid entry.
		if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0)
		{
			vaddress |= 0x80000000;
			bool good = !bad;
			if (!good)
			{
				// check for BLR before function
				u32 opcode = PowerPC::HostRead_Instruction(vaddress - 4);
				if (opcode == 0x4e800020)
				{
					// check for BLR at end of function
					opcode = PowerPC::HostRead_Instruction(vaddress + size - 4);
					if (opcode == 0x4e800020)
						good = true;
				}
			}
			if (good)
			{
				++good_count;
				AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION
			}
			else
			{
				++bad_count;
			}
		}
	}

	Index();
	if (bad)
		SuccessAlertT("Loaded %d good functions, ignored %d bad functions.", good_count, bad_count);
	return true;
}
Esempio n. 3
0
// This one can load both leftover map files on game discs (like Zelda), and mapfiles
// produced by SaveSymbolMap below.
// bad=true means carefully load map files that might not be from exactly the right version
bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad)
{
  File::IOFile f(filename, "r");
  if (!f)
    return false;

  // four columns are used in American Mensa Academy map files and perhaps other games
  bool four_columns = false;
  int good_count = 0;
  int bad_count = 0;

  char line[512];
  std::string section_name;
  while (fgets(line, 512, f.GetHandle()))
  {
    size_t length = strlen(line);
    if (length < 4)
      continue;

    if (length == 34 && strcmp(line, "  address  Size   address  offset\n") == 0)
    {
      four_columns = true;
      continue;
    }

    char temp[256];
    sscanf(line, "%255s", temp);

    if (strcmp(temp, "UNUSED") == 0)
      continue;

    // Support CodeWarrior and Dolphin map
    if (StringEndsWith(line, " section layout\n") || strcmp(temp, ".text") == 0 ||
        strcmp(temp, ".init") == 0)
    {
      section_name = temp;
      continue;
    }

    // Skip four columns' header.
    //
    // Four columns example:
    //
    // .text section layout
    //   Starting        Virtual
    //   address  Size   address
    //   -----------------------
    if (strcmp(temp, "Starting") == 0)
      continue;
    if (strcmp(temp, "address") == 0)
      continue;
    if (strcmp(temp, "-----------------------") == 0)
      continue;

    // Skip link map.
    //
    // Link map example:
    //
    // Link map of __start
    //  1] __start(func, weak) found in os.a __start.c
    //   2] __init_registers(func, local) found in os.a __start.c
    //    3] _stack_addr found as linker generated symbol
    // ...
    //           10] EXILock(func, global) found in exi.a EXIBios.c
    if (StringEndsWith(temp, "]"))
      continue;

    // TODO - Handle/Write a parser for:
    //  - Memory map
    //  - Link map
    //  - Linker generated symbols
    if (section_name.empty())
      continue;

    u32 address, vaddress, size, offset, alignment;
    char name[512], container[512];
    if (four_columns)
    {
      // sometimes there is no alignment value, and sometimes it is because it is an entry of
      // something else
      if (length > 37 && line[37] == ' ')
      {
        alignment = 0;
        sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name);
        char* s = strstr(line, "(entry of ");
        if (s)
        {
          sscanf(s + 10, "%511s", container);
          char* s2 = (strchr(container, ')'));
          if (s2 && container[0] != '.')
          {
            s2[0] = '\0';
            strcat(container, "::");
            strcat(container, name);
            strcpy(name, container);
          }
        }
      }
      else
      {
        sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset,
               &alignment, name);
      }
    }
    // some entries in the table have a function name followed by " (entry of " followed by a
    // container name, followed by ")"
    // instead of a space followed by a number followed by a space followed by a name
    else if (length > 27 && line[27] != ' ' && strstr(line, "(entry of "))
    {
      alignment = 0;
      sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name);
      char* s = strstr(line, "(entry of ");
      if (s)
      {
        sscanf(s + 10, "%511s", container);
        char* s2 = (strchr(container, ')'));
        if (s2 && container[0] != '.')
        {
          s2[0] = '\0';
          strcat(container, "::");
          strcat(container, name);
          strcpy(name, container);
        }
      }
    }
    else
    {
      sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &alignment, name);
    }

    const char* namepos = strstr(line, name);
    if (namepos != nullptr)  // would be odd if not :P
      strcpy(name, namepos);
    name[strlen(name) - 1] = 0;
    if (name[strlen(name) - 1] == '\r')
      name[strlen(name) - 1] = 0;

    // Check if this is a valid entry.
    if (strlen(name) > 0)
    {
      // Can't compute the checksum if not in RAM
      bool good = !bad && PowerPC::HostIsInstructionRAMAddress(vaddress) &&
                  PowerPC::HostIsInstructionRAMAddress(vaddress + size - 4);
      if (!good)
      {
        // check for BLR before function
        PowerPC::TryReadInstResult read_result = PowerPC::TryReadInstruction(vaddress - 4);
        if (read_result.valid && read_result.hex == 0x4e800020)
        {
          // check for BLR at end of function
          read_result = PowerPC::TryReadInstruction(vaddress + size - 4);
          good = read_result.valid && read_result.hex == 0x4e800020;
        }
      }
      if (good)
      {
        ++good_count;
        if (section_name == ".text" || section_name == ".init")
          AddKnownSymbol(vaddress, size, name, Symbol::Type::Function);
        else
          AddKnownSymbol(vaddress, size, name, Symbol::Type::Data);
      }
      else
      {
        ++bad_count;
      }
    }
  }

  Index();
  if (bad)
    SuccessAlertT("Loaded %d good functions, ignored %d bad functions.", good_count, bad_count);
  return true;
}