GP-4746 - PdbReader dump methods - output NameTable stream records;

modify more dumps to use Writer instead of StringBuilder
This commit is contained in:
ghizard 2024-07-03 16:42:48 +00:00
parent 7ebf70069b
commit 45f0ca63fa
26 changed files with 404 additions and 443 deletions

View File

@ -627,8 +627,9 @@ public abstract class AbstractPdb implements AutoCloseable {
* debugging only.
* @param writer {@link Writer}.
* @throws IOException on issue writing to the {@link Writer}.
* @throws CancelledException upon user cancellation
*/
public abstract void dumpDirectory(Writer writer) throws IOException;
public abstract void dumpDirectory(Writer writer) throws IOException, CancelledException;
//==============================================================================================
// Internal Data Methods
@ -658,19 +659,17 @@ public abstract class AbstractPdb implements AutoCloseable {
}
/**
* Dumps the Version Signature and Age. This package-protected method is for debugging only
* @return {@link String} of pretty output
* Dumps the Version Signature and Age to Writer. This package-protected method is for
* debugging only
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
protected String dumpVersionSignatureAge() {
StringBuilder builder = new StringBuilder();
builder.append("DirectoryHeader---------------------------------------------");
builder.append("\nversionNumber: ");
builder.append(versionNumber);
builder.append("\nsignature: ");
builder.append(Integer.toHexString(signature));
builder.append("\nage: ");
builder.append(pdbAge);
return builder.toString();
protected void dumpVersionSignatureAge(Writer writer) throws IOException {
writer.write("DirectoryHeader---------------------------------------------");
writer.write("\nversionNumber: " + versionNumber);
writer.write("\nsignature: " + Integer.toHexString(signature));
writer.write("\nage: " + pdbAge);
writer.write("End DirectoryHeader-----------------------------------------");
}
/**
@ -709,27 +708,25 @@ public abstract class AbstractPdb implements AutoCloseable {
}
/**
* Dumps the Parameters to a {@link String}. This package-protected method is for
* debugging only
* @return {@link String} of pretty output
* Dumps the Parameters to Writer. This package-protected method is for debugging only
* @param writer the writer
* @param monitor the task monitor
* @throws IOException on issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/
protected String dumpParameters() {
StringBuilder builder = new StringBuilder();
builder.append(nameTable.dump());
builder.append("\nParameters--------------------------------------------------\n");
protected void dumpParameters(Writer writer, TaskMonitor monitor)
throws IOException, CancelledException {
nameTable.dump(writer, monitor);
writer.write("\nParameters--------------------------------------------------\n");
for (int i = 0; i < parameters.size(); i++) {
builder.append(String.format("parameter[%d]: 0x%08x %d\n", i, parameters.get(i),
writer.write(String.format("parameter[%d]: 0x%08x %d\n", i, parameters.get(i),
parameters.get(i)));
}
builder.append("Booleans----------------------------------------------------");
builder.append("\nminimalDebugInfo: ");
builder.append(minimalDebugInfo);
builder.append("\nnoTypeMerge: ");
builder.append(noTypeMerge);
builder.append("\nhasIdStream: ");
builder.append(hasIdStream);
builder.append("\n");
return builder.toString();
writer.write("Booleans----------------------------------------------------");
writer.write("\nminimalDebugInfo: " + minimalDebugInfo);
writer.write("\nnoTypeMerge: " + noTypeMerge);
writer.write("\nhasIdStream: " + hasIdStream);
writer.write("\n");
}
/**

View File

@ -170,43 +170,38 @@ public abstract class AbstractSymbolInformation {
void dump(Writer writer) throws IOException, CancelledException, PdbException {
StringBuilder builder = new StringBuilder();
builder.append("AbstractSymbolInformation-----------------------------------\n");
dumpHashHeader(builder);
dumpHashBasics(builder);
dumpHashRecords(builder);
dumpHashHeader(writer);
dumpHashBasics(writer);
dumpHashRecords(writer);
builder.append("\nEnd AbstractSymbolInformation-------------------------------\n");
writer.write(builder.toString());
}
/**
* Debug method for dumping basic information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
protected void dumpHashBasics(StringBuilder builder) {
builder.append("HashBasics--------------------------------------------------\n");
builder.append("hashRecordsBitMapLength: ");
builder.append(hashRecordsBitMapLength);
builder.append("\nnumExtraBytes: ");
builder.append(numExtraBytes);
builder.append("\nnumHashRecords: ");
builder.append(numHashRecords);
builder.append("\nEnd HashBasics----------------------------------------------\n");
protected void dumpHashBasics(Writer writer) throws IOException {
writer.write("HashBasics--------------------------------------------------\n");
writer.write("hashRecordsBitMapLength: " + hashRecordsBitMapLength);
writer.write("\nnumExtraBytes: " + numExtraBytes);
writer.write("\nnumHashRecords: " + numHashRecords);
writer.write("\nEnd HashBasics----------------------------------------------\n");
}
/**
/**builder.append
* Debug method for dumping information from this {@link AbstractSymbolInformation} header
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
protected void dumpHashHeader(StringBuilder builder) {
builder.append("HashHeader--------------------------------------------------\n");
builder.append("headerSignature: ");
builder.append(headerSignature);
builder.append("\nversionNumber: ");
builder.append(versionNumber);
builder.append("\nlengthHashRecords: ");
builder.append(hashRecordsLength);
builder.append("\nlengthBuckets: ");
builder.append(bucketsLength);
builder.append("\nEnd HashHeader----------------------------------------------\n");
protected void dumpHashHeader(Writer writer) throws IOException {
writer.write("HashHeader--------------------------------------------------\n");
writer.write("headerSignature: " + headerSignature);
writer.write("\nversionNumber: " + versionNumber);
writer.write("\nlengthHashRecords: " + hashRecordsLength);
writer.write("\nlengthBuckets: " + bucketsLength);
writer.write("\nEnd HashHeader----------------------------------------------\n");
}
/**
@ -232,21 +227,22 @@ public abstract class AbstractSymbolInformation {
/**
* Debug method for dumping hash records from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException upon issue with writing to the writer
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/
protected void dumpHashRecords(StringBuilder builder)
throws CancelledException, PdbException {
protected void dumpHashRecords(Writer writer)
throws IOException, CancelledException, PdbException {
Set<SymbolHashRecord> hashRecords = getHashRecords();
builder.append("HashRecords-------------------------------------------------\n");
builder.append("numHashRecords: " + hashRecords.size() + "\n");
writer.write("HashRecords-------------------------------------------------\n");
writer.write("numHashRecords: " + hashRecords.size() + "\n");
for (SymbolHashRecord record : hashRecords) {
pdb.checkCancelled();
builder.append(
writer.write(
String.format("0X%08X 0X%04X\n", record.getOffset(), record.getReferenceCount()));
}
builder.append("\nEnd HashRecords---------------------------------------------\n");
writer.write("\nEnd HashRecords---------------------------------------------\n");
}
protected void deserializeHashHeader() throws PdbException, CancelledException, IOException {

View File

@ -15,10 +15,13 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* C11Lines information. As best as we know, only one of C11Lines or C13Lines can be found after
@ -250,41 +253,38 @@ public class C11Lines {
@Override
public String toString() {
try {
return dump();
}
catch (CancelledException e) {
return "";
}
return String.format("%s: numFiles = %d, numSegs = %d", getClass().getSimpleName(), cFile,
cSeg);
}
/**
* Dumps this class. This package-protected method is for debugging only.
* @return the {@link String} output.
* Dumps this class to Writer. This package-protected method is for debugging only
* @param writer the writer
* @param monitor the task monitor
* @throws CancelledException upon user cancellation
* @throws IOException upon issue writing to writer
*/
String dump() throws CancelledException {
StringBuilder builder = new StringBuilder();
builder.append("Lines-------------------------------------------------------\n");
builder.append("cFile: " + cFile + " cSeg: " + cSeg + "\n");
void dump(Writer writer, TaskMonitor monitor) throws CancelledException, IOException {
PdbReaderUtils.dumpHead(writer, this);
writer.write("cFile: " + cFile + " cSeg: " + cSeg + "\n");
for (int i = 0; i < cFile; i++) {
pdb.checkCancelled();
builder.append("baseSrcFile[" + i + "]: " + baseSrcFile.get(i) + "\n");
writer.write("baseSrcFile[" + i + "]: " + baseSrcFile.get(i) + "\n");
}
for (int i = 0; i < cSeg; i++) {
pdb.checkCancelled();
builder.append(i + ": start:" + startEnd.get(i).getStart() + " end: " +
writer.write(i + ": start:" + startEnd.get(i).getStart() + " end: " +
startEnd.get(i).getEnd() + " seg: " + seg.get(i) + "\n");
}
for (int i = 0; i < cFile; i++) {
pdb.checkCancelled();
builder.append(
writer.write(
" file[" + i + "]: cSeg: " + ccSegs.get(i) + " name: " + names.get(i) + "\n");
List<Integer> myBaseSrcLn = baseSrcLines.get(i);
List<C11LinesStartEnd> myStartEnds = startEnds.get(i);
for (int j = 0; j < ccSegs.get(i); j++) {
C11LinesStartEnd se = myStartEnds.get(j);
builder.append(" " + j + ": baseSrcLn: " + myBaseSrcLn.get(j) + " start: " +
writer.write(" " + j + ": baseSrcLn: " + myBaseSrcLn.get(j) + " start: " +
se.getStart() + " end: " + se.getEnd() + "\n");
}
List<Integer> segNums = segmentNumbers.get(i);
@ -294,15 +294,14 @@ public class C11Lines {
pdb.checkCancelled();
List<Long> segOffsets = fileSegOffsets.get(j);
List<Integer> segLineNums = fileSegLineNums.get(j);
builder.append(" seg[" + j + "]: Seg: " + segNums.get(j) + " cPair: " +
writer.write(" seg[" + j + "]: Seg: " + segNums.get(j) + " cPair: " +
segOffsets.size() + "\n");
for (int k = 0; k < segOffsets.size(); k++) {
builder.append(" " + segLineNums.get(k) + ":" + segOffsets.get(k) + "\n");
writer.write(" " + segLineNums.get(k) + ":" + segOffsets.get(k) + "\n");
}
}
}
builder.append("End Lines---------------------------------------------------\n");
return builder.toString();
PdbReaderUtils.dumpTail(writer, this);
}
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.*;
/**
* Debug header for various, yet-to-be-determined debug structures. {@link RvaVaDebugHeader}, an
* extension of this class, is used for PData and XData within {@link DebugData}.
@ -62,25 +64,31 @@ public class DebugHeader {
@Override
public String toString() {
return dump();
StringWriter writer = new StringWriter();
try {
dump(writer);
return writer.toString();
}
catch (IOException e) {
return "Issue in " + getClass().getSimpleName() + " toString(): " + e.getMessage();
}
}
/**
* Dumps this class. This package-protected method is for debugging only.
* @return the {@link String} output.
* Dumps this class to Writer. This package-protected method is for debugging only
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
String dump() {
StringBuilder builder = new StringBuilder();
builder.append("DebugHeader-------------------------------------------------\n");
dumpInternal(builder);
builder.append("End DebugHeader---------------------------------------------\n");
return builder.toString();
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
dumpInternal(writer);
PdbReaderUtils.dumpTail(writer, this);
}
protected void dumpInternal(StringBuilder builder) {
builder.append(String.format("headerVersion: 0X%08X\n", headerVersion));
builder.append(String.format("headerLength: 0X%08X\n", headerLength));
builder.append(String.format("dataLength: 0X%08X\n", dataLength));
protected void dumpInternal(Writer writer) throws IOException {
writer.write(String.format("headerVersion: 0X%08X\n", headerVersion));
writer.write(String.format("headerLength: 0X%08X\n", headerLength));
writer.write(String.format("dataLength: 0X%08X\n", dataLength));
}
}

View File

@ -71,13 +71,11 @@ public class GlobalSymbolInformation extends AbstractSymbolInformation {
*/
@Override
void dump(Writer writer) throws IOException, CancelledException, PdbException {
StringBuilder builder = new StringBuilder();
builder.append("GlobalSymbolInformation-------------------------------------\n");
dumpHashHeader(builder);
dumpHashBasics(builder);
dumpHashRecords(builder);
builder.append("\nEnd GlobalSymbolInformation---------------------------------\n");
writer.write(builder.toString());
writer.write("GlobalSymbolInformation-------------------------------------\n");
dumpHashHeader(writer);
dumpHashBasics(writer);
dumpHashRecords(writer);
writer.write("\nEnd GlobalSymbolInformation---------------------------------\n");
}
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.*;
/**
* Image Function Entry data seems to be the main data PData record of the {@link DebugData}.
*/
@ -61,21 +63,27 @@ public class ImageFunctionEntry {
@Override
public String toString() {
return dump();
StringWriter writer = new StringWriter();
try {
dump(writer);
return writer.toString();
}
catch (IOException e) {
return "Issue in " + getClass().getSimpleName() + " toString(): " + e.getMessage();
}
}
/**
* Dumps this class. This package-protected method is for debugging only.
* @return the {@link String} output.
* Dumps this class to Writer. This package-protected method is for debugging only
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
String dump() {
StringBuilder builder = new StringBuilder();
builder.append("ImageFunctionEntry------------------------------------------\n");
builder.append(String.format("startingAddress: 0X%08X\n", startingAddress));
builder.append(String.format("endingAddress: 0X%08X\n", endingAddress));
builder.append(String.format("endOfPrologueAddress: 0X%08X\n", endOfPrologueAddress));
builder.append("End ImageFunctionEntry--------------------------------------\n");
return builder.toString();
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
writer.write(String.format("startingAddress: 0X%08X\n", startingAddress));
writer.write(String.format("endingAddress: 0X%08X\n", endingAddress));
writer.write(String.format("endOfPrologueAddress: 0X%08X\n", endOfPrologueAddress));
PdbReaderUtils.dumpTail(writer, this);
}
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.*;
/**
* Linker Unwind Information that seems to be used in some XData types within {@link DebugData}.
*/
@ -61,24 +63,31 @@ public class LinkerUnwindInfo {
@Override
public String toString() {
return dump();
StringWriter writer = new StringWriter();
try {
dump(writer);
return writer.toString();
}
catch (IOException e) {
return "Issue in " + getClass().getSimpleName() + " toString(): " + e.getMessage();
}
}
/**
* Dumps this class. This package-protected method is for debugging only.
* @return the {@link String} output.
* Dumps this class to Writer. This package-protected method is for debugging only
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
String dump() {
StringBuilder builder = new StringBuilder();
builder.append("LinkerUnwindInfo--------------------------------------------\n");
dumpInternal(builder);
builder.append("End LinkerUnwindInfo----------------------------------------\n");
return builder.toString();
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
dumpInternal(writer);
PdbReaderUtils.dumpTail(writer, this);
}
protected void dumpInternal(StringBuilder builder) {
builder.append(String.format("version: 0X%04X\n", version));
builder.append(String.format("flags: 0X%04X\n", flags));
builder.append(String.format("dataLength: 0X%08X\n", dataLength));
protected void dumpInternal(Writer writer) throws IOException {
writer.write(String.format("version: 0X%04X\n", version));
writer.write(String.format("flags: 0X%04X\n", flags));
writer.write(String.format("dataLength: 0X%08X\n", dataLength));
}
}

View File

@ -345,7 +345,7 @@ public class Module {
writer.write("C11Lines----------------------------------------------------\n");
C11Lines c11lines = getLineInformation();
if (c11lines != null) {
writer.write(c11lines.dump());
c11lines.dump(writer, pdb.getMonitor());
}
writer.write("End C11Lines------------------------------------------------\n");
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
/**
@ -193,10 +195,11 @@ public abstract class ModuleInformation {
protected abstract void parseAdditionals(PdbByteReader reader) throws PdbException;
/**
* Dumps the Additionals. This method is for debugging only
* @return {@link String} of pretty output
* Dumps the Additionals to Writer. This method is for debugging only
* @param writer the writer
* @throws IOException upon issues writing to the writer
*/
protected abstract String dumpAdditionals();
protected abstract void dumpAdditionals(Writer writer) throws IOException;
//==============================================================================================
// Package-Protected Internals
@ -211,46 +214,34 @@ public abstract class ModuleInformation {
}
/**
* Dumps this module. This method is for debugging only
* @return {@link String} of pretty output
* Dumps this module to the Writer. This method is for debugging only
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
String dump() {
StringBuilder builder = new StringBuilder();
builder.append("ModuleInformation-------------------------------------------\n");
builder.append("modulePointer: ");
builder.append(modulePointer);
builder.append("\n");
builder.append(sectionContribution.dump());
builder.append("\nwrittenSinceOpen: ");
builder.append(writtenSinceOpen);
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
writer.write("modulePointer: " + modulePointer);
writer.write("\n");
sectionContribution.dump(writer);
writer.write("\nwrittenSinceOpen: " + writtenSinceOpen);
builder.append("\necSymbolicInformationEnabled: ");
builder.append(ecSymbolicInformationEnabled);
writer.write("\necSymbolicInformationEnabled: " + ecSymbolicInformationEnabled);
builder.append("\nspare: ");
builder.append(spare);
builder.append("\nindexToTSMList: ");
builder.append(indexToTSMList);
builder.append("\nstreamNumberDebugInformation: ");
builder.append(streamNumberDebugInformation);
builder.append("\nsizeLocalSymbolsDebugInformation: ");
builder.append(sizeLocalSymbolsDebugInformation);
builder.append("\nsizeLineNumberDebugInformation: ");
builder.append(sizeLineNumberDebugInformation);
builder.append("\nsizeC13StyleLineNumberInformation: ");
builder.append(sizeC13StyleLineNumberInformation);
builder.append("\nnumFilesContributing: ");
builder.append(numFilesContributing);
writer.write("\nspare: " + spare);
writer.write("\nindexToTSMList: " + indexToTSMList);
writer.write("\nstreamNumberDebugInformation: " + streamNumberDebugInformation);
writer.write("\nsizeLocalSymbolsDebugInformation: " + sizeLocalSymbolsDebugInformation);
writer.write("\nsizeLineNumberDebugInformation: " + sizeLineNumberDebugInformation);
writer.write("\nsizeC13StyleLineNumberInformation: " + sizeC13StyleLineNumberInformation);
writer.write("\nnumFilesContributing: " + numFilesContributing);
builder.append(dumpAdditionals());
dumpAdditionals(writer);
builder.append("\nmoduleName: ");
builder.append(moduleName);
builder.append("\nobjectFileName: ");
builder.append(objectFileName);
writer.write("\nmoduleName: " + moduleName);
writer.write("\nobjectFileName: " + objectFileName);
writer.write("\n");
builder.append("\nEnd ModuleInformation---------------------------------------\n");
return builder.toString();
PdbReaderUtils.dumpTail(writer, this);
}
}

View File

@ -15,6 +15,9 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
/**
* This class is the version of {@link ModuleInformation} for Microsoft v5.00 PDB.
*/
@ -43,8 +46,8 @@ public class ModuleInformation500 extends ModuleInformation {
}
@Override
protected String dumpAdditionals() {
return "";
protected void dumpAdditionals(Writer writer) throws IOException {
// do nothing
}
}

View File

@ -15,6 +15,9 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
/**
* This class is the version of {@link ModuleInformation} for Microsoft v6.00 PDB.
*/
@ -44,13 +47,9 @@ public class ModuleInformation600 extends ModuleInformation {
}
@Override
protected String dumpAdditionals() {
StringBuilder builder = new StringBuilder();
builder.append("\nnameIndexSourceFile: ");
builder.append(nameIndexSourceFile);
builder.append("\nnameIndexCompilerPdbPath: ");
builder.append(nameIndexCompilerPdbPath);
return builder.toString();
protected void dumpAdditionals(Writer writer) throws IOException {
writer.write("\nnameIndexSourceFile: " + nameIndexSourceFile);
writer.write("\nnameIndexCompilerPdbPath: " + nameIndexCompilerPdbPath);
}
}

View File

@ -16,9 +16,11 @@
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* This class represents Name Table component of a PDB file. This class is only
@ -231,66 +233,73 @@ public class NameTable {
/**
* Dumps the Name Table. This method is for debugging only.
* @return {@link String} of pretty output.
* @param writer the writer to which to write the dump
* @param monitor the task monitor
* @throws CancelledException upon user cancellation
* @throws IOException upon issue writing to writer
*/
protected String dump() {
StringBuilder builder = new StringBuilder();
builder.append("NameTable---------------------------------------------------");
builder.append("\nnameBufferSize: ");
builder.append(nameBufferSize);
builder.append("\nnumPairs: ");
builder.append(numPairs);
builder.append("\ndomainSize: ");
builder.append(domainSize);
builder.append("\nmaxPossiblePresent: ");
builder.append(presentList.getMaxPossible());
builder.append("\nPresent: {");
void dump(Writer writer, TaskMonitor monitor) throws CancelledException, IOException {
PdbReaderUtils.dumpHead(writer, this);
writer.write("\nnameBufferSize: " + nameBufferSize);
writer.write("\nnumPairs: " + numPairs);
writer.write("\ndomainSize: " + domainSize);
writer.write("\nmaxPossiblePresent: " + presentList.getMaxPossible());
writer.write("\nPresent: {");
boolean firstSeen = false;
for (int i = 0; i < presentList.getMaxPossible(); i++) {
if (presentList.contains(i)) {
if (firstSeen) {
builder.append(", ");
writer.write(", ");
}
else {
firstSeen = true;
}
builder.append(i);
writer.write("" + i);
}
}
builder.append("}");
builder.append("\nmaxPossibleDeleted: ");
builder.append(deletedList.getMaxPossible());
builder.append("\nDeleted: {");
writer.write("}");
writer.write("\nmaxPossibleDeleted: " + deletedList.getMaxPossible());
writer.write("\nDeleted: {");
firstSeen = false;
for (int i = 0; i < deletedList.getMaxPossible(); i++) {
if (deletedList.contains(i)) {
if (firstSeen) {
builder.append(", ");
writer.write(", ");
}
else {
firstSeen = true;
}
builder.append(i);
writer.write("" + i);
}
}
builder.append("}\n");
builder.append("------------------------------------------------------------\n");
writer.write("}\n");
writer.write("------------------------------------------------------------\n");
for (String name : streamNumbersByName.keySet()) {
builder.append(name);
builder.append(" : ");
builder.append(streamNumbersByName.get(name));
builder.append("\n");
writer.write(name + " : " + streamNumbersByName.get(name) + "\n");
}
builder.append("------------------------------------------------------------\n");
writer.write("------------------------------------------------------------\n");
for (int streamNumber : namesByStreamNumber.keySet()) {
builder.append(streamNumber);
builder.append(" : ");
builder.append(namesByStreamNumber.get(streamNumber));
builder.append("\n");
writer.write(streamNumber + " : " + namesByStreamNumber.get(streamNumber) + "\n");
}
dumpMapTables(writer, monitor);
PdbReaderUtils.dumpTail(writer, this);
}
private void dumpMapTables(Writer writer, TaskMonitor monitor)
throws CancelledException, IOException {
for (int streamNumber : streamNumbers) {
pdb.checkCancelled();
writer.write("StreamNameTable---------------------------------------------\n");
writer.write("streamNumber: " + streamNumber + "\n");
Map<Integer, String> stringsByOffset = stringTablesByStreamNumber.get(streamNumber);
ArrayList<Integer> sortedKeys = new ArrayList<>(stringsByOffset.keySet());
Collections.sort(sortedKeys);
for (int offset : sortedKeys) {
String str = stringsByOffset.get(offset);
writer.write(offset + ": " + str + "\n");
}
writer.write("End StreamNameTable-----------------------------------------\n");
}
// TODO: output map entries for each table.
builder.append("End NameTable-----------------------------------------------\n");
return builder.toString();
}
}

View File

@ -60,9 +60,7 @@ public class Pdb200 extends AbstractPdb {
@Override
public void dumpDirectory(Writer writer) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append(dumpVersionSignatureAge());
writer.write(builder.toString());
dumpVersionSignatureAge(writer);
}
}

View File

@ -60,12 +60,10 @@ public class Pdb400 extends AbstractPdb {
}
@Override
public void dumpDirectory(Writer writer) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append(dumpVersionSignatureAge());
builder.append("\n");
builder.append(dumpParameters());
writer.write(builder.toString());
public void dumpDirectory(Writer writer) throws IOException, CancelledException {
dumpVersionSignatureAge(writer);
writer.write("\n");
dumpParameters(writer, getMonitor());
}
}

View File

@ -61,31 +61,14 @@ public class Pdb700 extends AbstractPdb {
}
@Override
public void dumpDirectory(Writer writer) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append(dumpVersionSignatureAge());
builder.append("\n");
builder.append(dumpGUID());
builder.append("\n");
builder.append(dumpParameters());
writer.write(builder.toString());
}
//==============================================================================================
// Internal Data Methods
//==============================================================================================
/**
* Dumps the GUID. This method is for debugging only
* @return {@link String} of pretty output
*/
protected String dumpGUID() {
if (guid == null) {
return "";
public void dumpDirectory(Writer writer) throws IOException, CancelledException {
dumpVersionSignatureAge(writer);
writer.write("\n");
if (guid != null) {
writer.write("GUID: " + guid);
writer.write("\n");
}
StringBuilder builder = new StringBuilder();
builder.append("GUID: ");
builder.append(guid);
return builder.toString();
dumpParameters(writer, getMonitor());
}
}

View File

@ -516,7 +516,7 @@ public abstract class PdbDebugInfo {
protected void dumpModuleInformation(Writer writer) throws IOException, CancelledException {
for (ModuleInformation information : moduleInformationList) {
pdb.checkCancelled();
writer.write(information.dump());
information.dump(writer);
writer.write("\n");
}
}
@ -531,7 +531,7 @@ public abstract class PdbDebugInfo {
protected void dumpSectionContributions(Writer writer) throws IOException, CancelledException {
for (SectionContribution contribution : sectionContributionList) {
pdb.checkCancelled();
writer.write(contribution.dump());
contribution.dump(writer);
writer.write("\n");
}
}
@ -546,7 +546,7 @@ public abstract class PdbDebugInfo {
protected void dumpSegmentMap(Writer writer) throws IOException, CancelledException {
for (SegmentMapDescription description : segmentMapList) {
pdb.checkCancelled();
writer.write(description.dump());
description.dump(writer);
writer.write("\n");
}
}

View File

@ -203,19 +203,18 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
*/
@Override
void dump(Writer writer) throws IOException, CancelledException, PdbException {
StringBuilder builder = new StringBuilder();
builder.append("PublicSymbolInformation-------------------------------------\n");
dumpPubHeader(builder);
dumpHashHeader(builder);
dumpHashBasics(builder);
dumpHashRecords(builder);
PdbReaderUtils.dumpHead(writer, this);
dumpPubHeader(writer);
dumpHashHeader(writer);
dumpHashBasics(writer);
dumpHashRecords(writer);
dumpAddressMap(builder);
dumpThunkMap(builder);
dumpSectionMap(builder);
dumpAddressMap(writer);
dumpThunkMap(writer);
dumpSectionMap(writer);
writer.write("\n");
builder.append("\nEnd PublicSymbolInformation---------------------------------\n");
writer.write(builder.toString());
PdbReaderUtils.dumpTail(writer, this);
}
//==============================================================================================
@ -239,23 +238,23 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
/**
* Debug method for dumping Address Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/
private void dumpAddressMap(StringBuilder builder)
private void dumpAddressMap(Writer writer)
throws CancelledException, IOException, PdbException {
builder.append("AddressMapSymbolOffsets-------------------------------------\n");
writer.write("AddressMapSymbolOffsets-------------------------------------\n");
List<Long> myAddressMapSymbolOffsets = getAddressMapSymbolOffsets();
builder.append("numAddressMapSymbolOffsets: " + myAddressMapSymbolOffsets.size() + "\n");
writer.write("numAddressMapSymbolOffsets: " + myAddressMapSymbolOffsets.size() + "\n");
int num = 0;
for (Long val : myAddressMapSymbolOffsets) {
pdb.checkCancelled();
builder.append(String.format("0X%08X: 0X%012X\n", num++, val));
writer.write(String.format("0X%08X: 0X%012X\n", num++, val));
}
builder.append("\nEnd AddressMapSymbolOffsets---------------------------------\n");
writer.write("\nEnd AddressMapSymbolOffsets---------------------------------\n");
}
/**
@ -279,24 +278,24 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
/**
* Debug method for dumping Thunk Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/
private void dumpThunkMap(StringBuilder builder)
private void dumpThunkMap(Writer writer)
throws CancelledException, IOException, PdbException {
Map<Integer, Integer> myThunkTargetOffsetsByTableOffset =
getThunkTargetOffsetsByTableOffset();
builder.append("ThunkMap----------------------------------------------------\n");
builder.append("numThunkTargetOffsetsByTableOffset: " +
writer.write("ThunkMap----------------------------------------------------\n");
writer.write("numThunkTargetOffsetsByTableOffset: " +
myThunkTargetOffsetsByTableOffset.size() + "\n");
for (Map.Entry<Integer, Integer> entry : myThunkTargetOffsetsByTableOffset.entrySet()) {
pdb.checkCancelled();
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
writer.write(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
}
builder.append("\nEnd ThunkMap------------------------------------------------\n");
writer.write("\nEnd ThunkMap------------------------------------------------\n");
}
/**
@ -320,51 +319,43 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
/**
* Debug method for dumping Section Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/
private void dumpSectionMap(StringBuilder builder)
private void dumpSectionMap(Writer writer)
throws CancelledException, IOException, PdbException {
Map<Integer, Integer> myAbsoluteOffsetsBySectionNumber =
getAbsoluteOffsetsBySectionNumber();
builder.append("SectionMap--------------------------------------------------\n");
builder.append(
writer.write("SectionMap--------------------------------------------------\n");
writer.write(
"numAbsoluteOffsetsBySectionNumber: " + myAbsoluteOffsetsBySectionNumber.size() + "\n");
for (Map.Entry<Integer, Integer> entry : myAbsoluteOffsetsBySectionNumber.entrySet()) {
pdb.checkCancelled();
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
writer.write(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
}
builder.append("\nEnd SectionMap----------------------------------------------\n");
writer.write("\nEnd SectionMap----------------------------------------------\n");
}
/**
* Debug method for dumping the {@link PublicSymbolInformation} header
* @param builder {@link StringBuilder} to which to dump the information
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
private void dumpPubHeader(StringBuilder builder) {
builder.append("PublicSymbolInformationHeader-------------------------------\n");
builder.append("symbolHashLength: ");
builder.append(symbolHashLength);
builder.append("\naddressMapLength: ");
builder.append(addressMapLength);
builder.append("\nnumThunks: ");
builder.append(numThunks);
builder.append("\nthunkSize: ");
builder.append(thunkSize);
builder.append("\niSectionThunkTable: ");
builder.append(iSectionThunkTable);
builder.append("\noffsetThunkTable: ");
builder.append(offsetThunkTable);
builder.append("\nnumSections: ");
builder.append(numSections);
builder.append("\nthunkMapLength: ");
builder.append(thunkMapLength);
builder.append("\nthunkTableLength: ");
builder.append(thunkTableLength);
builder.append("\nEnd PublicSymbolInformationHeader---------------------------\n");
private void dumpPubHeader(Writer writer) throws IOException {
writer.write("PublicSymbolInformationHeader-------------------------------\n");
writer.write("symbolHashLength: " + symbolHashLength);
writer.write("\naddressMapLength: " + addressMapLength);
writer.write("\nnumThunks: " + numThunks);
writer.write("\nthunkSize: " + thunkSize);
writer.write("\niSectionThunkTable: " + iSectionThunkTable);
writer.write("\noffsetThunkTable: " + offsetThunkTable);
writer.write("\nnumSections: " + numSections);
writer.write("\nthunkMapLength: " + thunkMapLength);
writer.write("\nthunkTableLength: " + thunkTableLength);
writer.write("\nEnd PublicSymbolInformationHeader---------------------------\n");
}
void deserializePubHeader() throws PdbException, CancelledException, IOException {

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.math.BigInteger;
/**
@ -75,23 +77,14 @@ public class RvaVaDebugHeader extends DebugHeader {
}
@Override
String dump() {
StringBuilder builder = new StringBuilder();
builder.append("RvaVaDebugHeader--------------------------------------------\n");
dumpInternal(builder);
builder.append("End RvaVaDebugHeader----------------------------------------\n");
return builder.toString();
}
@Override
protected void dumpInternal(StringBuilder builder) {
super.dumpInternal(builder);
builder.append(String.format("relativeVirtualAddressDataBase: 0X%08X\n",
protected void dumpInternal(Writer writer) throws IOException {
super.dumpInternal(writer);
writer.write(String.format("relativeVirtualAddressDataBase: 0X%08X\n",
relativeVirtualAddressDataBase));
builder.append(
writer.write(
String.format("virtualAddressImageBase: 0X%016X\n", virtualAddressImageBase));
builder.append(String.format("unsignedIntReserved1: 0X%08X\n", unsignedIntReserved1));
builder.append(String.format("unsignedIntReserved2: 0X%08X\n", unsignedIntReserved2));
writer.write(String.format("unsignedIntReserved1: 0X%08X\n", unsignedIntReserved1));
writer.write(String.format("unsignedIntReserved2: 0X%08X\n", unsignedIntReserved2));
}
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.*;
/**
* This class represents Section Contribution component of a PDB file. This class is only
* suitable for reading; not for writing or modifying a PDB.
@ -62,7 +64,14 @@ public abstract class SectionContribution {
@Override
public String toString() {
return dump();
StringWriter writer = new StringWriter();
try {
dump(writer);
return writer.toString();
}
catch (IOException e) {
return "Issue in " + getClass().getSimpleName() + " toString(): " + e.getMessage();
}
}
//==============================================================================================
@ -77,23 +86,23 @@ public abstract class SectionContribution {
/**
* Dumps the SectionContribution. This method is for debugging only
* @return {@link String} of pretty output
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
abstract String dumpInternals();
abstract void dumpInternals(Writer writer) throws IOException;
//==============================================================================================
// Package-Protected Internals
//==============================================================================================
/**
* Dumps the Section Contribution. This method is for debugging only
* @return {@link String} of pretty output
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
String dump() {
StringBuilder builder = new StringBuilder();
builder.append("SectionContribution-----------------------------------------\n");
builder.append(dumpInternals());
builder.append("\nEnd SectionContribution-------------------------------------\n");
return builder.toString();
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
dumpInternals(writer);
PdbReaderUtils.dumpTail(writer, this);
}
}

View File

@ -15,6 +15,9 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
/**
* This class is the version of {@link SectionContribution} for Microsoft v14.00 PDB.
*/
@ -38,24 +41,16 @@ public class SectionContribution1400 extends SectionContribution {
}
@Override
String dumpInternals() {
StringBuilder builder = new StringBuilder();
builder.append("isect: ");
builder.append(isect);
builder.append("\noffset: ");
builder.append(offset);
builder.append("\nlength: ");
builder.append(length);
builder.append(String.format("\ncharacteristics: 0X%08X", characteristics));
builder.append("\nimod: ");
builder.append(imod);
builder.append("\ndataCrc: ");
builder.append(dataCrc);
builder.append("\nrelocationCrc: ");
builder.append(relocationCrc);
builder.append("\nunknownSectionContributionField: ");
builder.append(unknownSectionContributionField);
return builder.toString();
void dumpInternals(Writer writer) throws IOException {
writer.write("isect: " + isect);
writer.write("\noffset: " + offset);
writer.write("\nlength: " + length);
writer.write(String.format("\ncharacteristics: 0X%08X", characteristics));
writer.write("\nimod: " + imod);
writer.write("\ndataCrc: " + dataCrc);
writer.write("\nrelocationCrc: " + relocationCrc);
writer.write("\nunknownSectionContributionField: " + unknownSectionContributionField);
writer.write("\n");
}
}

View File

@ -15,6 +15,9 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
/**
* This class is the version of {@link SectionContribution} for Microsoft v2.00 PDB.
*/
@ -32,17 +35,12 @@ public class SectionContribution200 extends SectionContribution {
}
@Override
String dumpInternals() {
StringBuilder builder = new StringBuilder();
builder.append("isect: ");
builder.append(isect);
builder.append("\noffset: ");
builder.append(offset);
builder.append("\nlength: ");
builder.append(length);
builder.append("\nimod: ");
builder.append(imod);
return builder.toString();
void dumpInternals(Writer writer) throws IOException {
writer.write("isect: " + isect);
writer.write("\noffset: " + offset);
writer.write("\nlength: " + length);
writer.write("\nimod: " + imod);
writer.write("\n");
}
}

View File

@ -15,6 +15,9 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
/**
* This class is the version of {@link SectionContribution} for Microsoft v4.00 PDB.
*/
@ -34,18 +37,13 @@ public class SectionContribution400 extends SectionContribution {
}
@Override
String dumpInternals() {
StringBuilder builder = new StringBuilder();
builder.append("isect: ");
builder.append(isect);
builder.append("\noffset: ");
builder.append(offset);
builder.append("\nlength: ");
builder.append(length);
builder.append(String.format("\ncharacteristics: 0X%08X", characteristics));
builder.append("\nimod: ");
builder.append(imod);
return builder.toString();
void dumpInternals(Writer writer) throws IOException {
writer.write("isect: " + isect);
writer.write("\noffset: " + offset);
writer.write("\nlength: " + length);
writer.write(String.format("\ncharacteristics: 0X%08X", characteristics));
writer.write("\nimod: " + imod);
writer.write("\n");
}
}

View File

@ -15,6 +15,9 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
/**
* This class is the version of {@link SectionContribution} for Microsoft v6.00 PDB.
*/
@ -37,22 +40,15 @@ public class SectionContribution600 extends SectionContribution {
}
@Override
String dumpInternals() {
StringBuilder builder = new StringBuilder();
builder.append("isect: ");
builder.append(isect);
builder.append("\noffset: ");
builder.append(offset);
builder.append("\nlength: ");
builder.append(length);
builder.append(String.format("\ncharacteristics: 0X%08X", characteristics));
builder.append("\nimod: ");
builder.append(imod);
builder.append("\ndataCrc: ");
builder.append(dataCrc);
builder.append("\nrelocationCrc: ");
builder.append(relocationCrc);
return builder.toString();
void dumpInternals(Writer writer) throws IOException {
writer.write("isect: " + isect);
writer.write("\noffset: " + offset);
writer.write("\nlength: " + length);
writer.write(String.format("\ncharacteristics: 0X%08X", characteristics));
writer.write("\nimod: " + imod);
writer.write("\ndataCrc: " + dataCrc);
writer.write("\nrelocationCrc: " + relocationCrc);
writer.write("\n");
}
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.*;
/**
* This class represents Segment Map Description component of a PDB file. This class is only
* suitable for reading; not for writing or modifying a PDB.
@ -123,34 +125,33 @@ public class SegmentMapDescription {
@Override
public String toString() {
return dump();
StringWriter writer = new StringWriter();
try {
dump(writer);
return writer.toString();
}
catch (IOException e) {
return "Issue in " + getClass().getSimpleName() + " toString(): " + e.getMessage();
}
}
/**
* Dumps the {@link SegmentMapDescription}. This method is for debugging only.
* @return {@link String} of pretty output.
* Dumps the {@link SegmentMapDescription} to writer. This method is for debugging only
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
protected String dump() {
StringBuilder builder = new StringBuilder();
builder.append("SegmentMapDescription---------------------------------------");
builder.append("\nflags: ");
builder.append(String.format("0x%04x", flags));
builder.append("\novl: ");
builder.append(ovl);
builder.append("\ngroup: ");
builder.append(group);
builder.append("\nframe: ");
builder.append(frame);
builder.append("\nsegNameIndex: ");
builder.append(segNameIndex);
builder.append("; classNameIndex: ");
builder.append(classNameIndex);
builder.append("; segOffset: ");
builder.append(segOffset);
builder.append("; segLength: ");
builder.append(segLength);
builder.append("\nEnd SegmentMapDescription-----------------------------------\n");
return builder.toString();
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
writer.write(String.format("\nflags: 0x%04x", flags));
writer.write("\novl: " + ovl);
writer.write("\ngroup: " + group);
writer.write("\nframe: " + frame);
writer.write("\nsegNameIndex: " + segNameIndex);
writer.write("; classNameIndex: " + classNameIndex);
writer.write("; segOffset: " + segOffset);
writer.write("; segLength: " + segLength);
writer.write("\n");
PdbReaderUtils.dumpTail(writer, this);
}
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -480,32 +480,23 @@ public abstract class TypeProgramInterface implements TPI {
/**
* Dumps the this {@link TypeProgramInterfaceHash}. This method is for debugging only
* @return {@link String} of pretty output
* @param writer the writer
* @throws IOException upon issue with writing to the writer
*/
protected String dump() {
StringBuilder builder = new StringBuilder();
builder.append("Hash--------------------------------------------------------");
builder.append("\nhashStreamNumber: ");
builder.append(hashStreamNumber);
builder.append("\nhashStreamNumberAuxiliary: ");
builder.append(hashStreamNumberAuxiliary);
builder.append("\nhashKeySize: ");
builder.append(hashKeySize);
builder.append("\nnumHashBins: ");
builder.append(numHashBins);
builder.append("\noffsetHashVals: ");
builder.append(offsetHashVals);
builder.append("\nlengthHashVals: ");
builder.append(lengthHashVals);
builder.append("\noffsetTypeIndexOffsetPairs: ");
builder.append(offsetTypeIndexOffsetPairs);
builder.append("\nlengthTypeIndexOffsetPairs: ");
builder.append(lengthTypeIndexOffsetPairs);
builder.append("\noffsetHashAdjustment: ");
builder.append(offsetHashAdjustment);
builder.append("\nlengthHashAdjustment: ");
builder.append(lengthHashAdjustment);
return builder.toString();
void dump(Writer writer) throws IOException {
PdbReaderUtils.dumpHead(writer, this);
writer.write("\nhashStreamNumber: " + hashStreamNumber);
writer.write("\nhashStreamNumberAuxiliary: " + hashStreamNumberAuxiliary);
writer.write("\nhashKeySize: " + hashKeySize);
writer.write("\nnumHashBins: " + numHashBins);
writer.write("\noffsetHashVals: " + offsetHashVals);
writer.write("\nlengthHashVals: " + lengthHashVals);
writer.write("\noffsetTypeIndexOffsetPairs: " + offsetTypeIndexOffsetPairs);
writer.write("\nlengthTypeIndexOffsetPairs: " + lengthTypeIndexOffsetPairs);
writer.write("\noffsetHashAdjustment: " + offsetHashAdjustment);
writer.write("\nlengthHashAdjustment: " + lengthHashAdjustment);
writer.write("\n");
PdbReaderUtils.dumpTail(writer, this);
}
}

View File

@ -52,20 +52,13 @@ public class TypeProgramInterface800 extends TypeProgramInterface {
@Override
protected void dumpHeader(Writer writer) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("\nversionNumber: ");
builder.append(versionNumber);
builder.append("\nheaderLength: ");
builder.append(headerLength);
builder.append("\ntypeIndexMin: ");
builder.append(typeIndexMin);
builder.append("\ntypeIndexMaxExclusive: ");
builder.append(typeIndexMaxExclusive);
builder.append("\ndataLength: ");
builder.append(dataLength);
builder.append("\n");
builder.append(hash.dump());
writer.write(builder.toString());
writer.write("\nversionNumber: " + versionNumber);
writer.write("\nheaderLength: " + headerLength);
writer.write("\ntypeIndexMin: " + typeIndexMin);
writer.write("\ntypeIndexMaxExclusive: " + typeIndexMaxExclusive);
writer.write("\ndataLength: " + dataLength);
writer.write("\n");
hash.dump(writer);
}
}