Commits

spencercw  committed 03da2b0

Add support for decoding full filename paths in debug symbols from patched versions of SDCC.

  • Participants
  • Parent commits 61faaef
  • Branches debugger

Comments (0)

Files changed (2)

File gb_emulator/include/gb_emulator/cdb_file.h

 		std::string &scopeDetail);
 	ParseError parseType(const std::string &typeStr, boost::shared_ptr<TypeChain> &typeChain);
 
+	bool decodeFilename(const std::string &filename, std::string &decodedFilename);
+
 	// Finds the function which covers the given address, if any.
 	boost::shared_ptr<Symbol> findFunction(uint64_t address);
 };

File gb_emulator/src/cdb_file.cpp

 					}
 
 					CLine line;
-					line.filename = results[1];
+					if (!decodeFilename(results[1], line.filename))
+					{
+						// Decode failed; just use the name provided
+						line.filename = results[1];
+					}
 					line.line = lexical_cast<unsigned>(results[2]);
 					line.level = lexical_cast<unsigned>(results[3]);
 					line.block = lexical_cast<unsigned>(results[4]);
 	return PARSE_OK;
 }
 
+bool CdbFile::decodeFilename(const string &filename, string &decodedFilename)
+{
+	// The standard CDB format only includes the filename of the source file; not the full path.
+	// This is an issue because it makes it impossible to automatically locate source files
+	// (particularly those in libraries not part of the project). To work around this, SDCC has been
+	// patched to include an encoded version of the full path. This simple encoding is similar to
+	// URL encoding, except an underscore ('_') is used in place of the percent symbol. All
+	// characters but letters, numbers and the period ('.') are encoded).
+
+	enum State
+	{
+		NORMAL,
+		FIRST_NIBBLE,
+		SECOND_NIBBLE
+	};
+
+	decodedFilename.reserve(filename.length());
+	State state = NORMAL;
+	char byte;
+	for (string::const_iterator ch = filename.begin(), end = filename.end(); ch != end; ++ch)
+	{
+		switch (state)
+		{
+		case NORMAL:
+			if ((*ch >= '0' && *ch <= '9') || (*ch >= 'A' && *ch <= 'Z') ||
+				(*ch >= 'a' && *ch <= 'z') || *ch == '.')
+			{
+				decodedFilename += *ch;
+			}
+			else if (*ch == '_')
+			{
+				state = FIRST_NIBBLE;
+			}
+			else
+			{
+				return false;
+			}
+			break;
+
+		case FIRST_NIBBLE:
+		case SECOND_NIBBLE:
+			{
+				char nibble;
+				if (*ch >= '0' && *ch <= '9')
+				{
+					nibble = *ch - '0';
+				}
+				else if (*ch >= 'a' && *ch <= 'z')
+				{
+					nibble = *ch - 'a' + 0xa;
+				}
+				else if (*ch >= 'A' && *ch <= 'Z')
+				{
+					nibble = *ch - 'A' + 0xa;
+				}
+				else
+				{
+					return false;
+				}
+
+				if (state == FIRST_NIBBLE)
+				{
+					byte = nibble << 4;
+					state = SECOND_NIBBLE;
+				}
+				else
+				{
+					byte |= nibble;
+					decodedFilename.push_back(byte);
+					state = NORMAL;
+				}
+			}
+			break;
+		}
+	}
+
+	if (state != NORMAL)
+	{
+		// String ended in the middle of an encoded byte
+		return false;
+	}
+
+	return true;
+}
+
 shared_ptr<CdbFile::Symbol> CdbFile::findFunction(uint64_t address)
 {
 	for (map<string, shared_ptr<Symbol> >::iterator symbol = symbols_.begin(), end = symbols_.end();