github.com/saferwall/pe@v1.5.2/debug.go (about)

     1  // Copyright 2018 Saferwall. All rights reserved.
     2  // Use of this source code is governed by Apache v2 license
     3  // license that can be found in the LICENSE file.
     4  
     5  package pe
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"fmt"
    11  )
    12  
    13  // The following values are defined for the Type field of the debug directory entry:
    14  const (
    15  	// An unknown value that is ignored by all tools.
    16  	ImageDebugTypeUnknown = 0
    17  
    18  	// The COFF debug information (line numbers, symbol table, and string table).
    19  	// This type of debug information is also pointed to by fields in the file headers.
    20  	ImageDebugTypeCOFF = 1
    21  
    22  	// The Visual C++ debug information.
    23  	ImageDebugTypeCodeView = 2
    24  
    25  	// The frame pointer omission (FPO) information. This information tells the
    26  	// debugger how to interpret nonstandard stack frames, which use the EBP
    27  	// register for a purpose other than as a frame pointer.
    28  	ImageDebugTypeFPO = 3
    29  
    30  	// The location of DBG file.
    31  	ImageDebugTypeMisc = 4
    32  
    33  	// A copy of .pdata section.
    34  	ImageDebugTypeException = 5
    35  
    36  	// Reserved.
    37  	ImageDebugTypeFixup = 6
    38  
    39  	// The mapping from an RVA in image to an RVA in source image.
    40  	ImageDebugTypeOMAPToSrc = 7
    41  
    42  	// The mapping from an RVA in source image to an RVA in image.
    43  	ImageDebugTypeOMAPFromSrc = 8
    44  
    45  	// Reserved for Borland.
    46  	ImageDebugTypeBorland = 9
    47  
    48  	// Reserved.
    49  	ImageDebugTypeReserved = 10
    50  
    51  	// Reserved.
    52  	ImageDebugTypeCLSID = 11
    53  
    54  	// Visual C++ features (/GS counts /sdl counts and guardN counts).
    55  	ImageDebugTypeVCFeature = 12
    56  
    57  	// Pogo aka PGO aka Profile Guided Optimization.
    58  	ImageDebugTypePOGO = 13
    59  
    60  	// Incremental Link Time Code Generation (iLTCG).
    61  	ImageDebugTypeILTCG = 14
    62  
    63  	// Intel MPX.
    64  	ImageDebugTypeMPX = 15
    65  
    66  	// PE determinism or reproducibility.
    67  	ImageDebugTypeRepro = 16
    68  
    69  	// Extended DLL characteristics bits.
    70  	ImageDebugTypeExDllCharacteristics = 20
    71  )
    72  
    73  const (
    74  	// CVSignatureRSDS represents the CodeView signature 'SDSR'.
    75  	CVSignatureRSDS = 0x53445352
    76  
    77  	// CVSignatureNB10 represents the CodeView signature 'NB10'.
    78  	CVSignatureNB10 = 0x3031424e
    79  )
    80  
    81  const (
    82  	// FrameFPO indicates a frame of type FPO.
    83  	FrameFPO = 0x0
    84  
    85  	// FrameTrap indicates a frame of type Trap.
    86  	FrameTrap = 0x1
    87  
    88  	// FrameTSS indicates a frame of type TSS.
    89  	FrameTSS = 0x2
    90  
    91  	// FrameNonFPO indicates a frame of type Non-FPO.
    92  	FrameNonFPO = 0x3
    93  )
    94  
    95  // DllCharacteristicsExType represents a DLL Characteristics type.
    96  type DllCharacteristicsExType uint32
    97  
    98  const (
    99  	// ImageDllCharacteristicsExCETCompat indicates that the image is CET
   100  	// compatible.
   101  	ImageDllCharacteristicsExCETCompat = 0x0001
   102  )
   103  
   104  const (
   105  	// POGOTypePGU represents a signature for an undocumented PGO sub type.
   106  	POGOTypePGU = 0x50475500
   107  	// POGOTypePGI represents a signature for an undocumented PGO sub type.
   108  	POGOTypePGI = 0x50474900
   109  	// POGOTypePGO represents a signature for an undocumented PGO sub type.
   110  	POGOTypePGO = 0x50474F00
   111  	// POGOTypeLTCG represents a signature for an undocumented PGO sub type.
   112  	POGOTypeLTCG = 0x4c544347
   113  )
   114  
   115  // ImageDebugDirectoryType represents the type of a debug directory.
   116  type ImageDebugDirectoryType uint32
   117  
   118  // ImageDebugDirectory represents the IMAGE_DEBUG_DIRECTORY structure.
   119  // This directory indicates what form of debug information is present
   120  // and where it is. This directory consists of an array of debug directory
   121  // entries whose location and size are indicated in the image optional header.
   122  type ImageDebugDirectory struct {
   123  	// Reserved, must be 0.
   124  	Characteristics uint32 `json:"characteristics"`
   125  
   126  	// The time and date that the debug data was created.
   127  	TimeDateStamp uint32 `json:"time_date_stamp"`
   128  
   129  	// The major version number of the debug data format.
   130  	MajorVersion uint16 `json:"major_version"`
   131  
   132  	// The minor version number of the debug data format.
   133  	MinorVersion uint16 `json:"minor_version"`
   134  
   135  	// The format of debugging information. This field enables support of
   136  	// multiple debuggers.
   137  	Type ImageDebugDirectoryType `json:"type"`
   138  
   139  	// The size of the debug data (not including the debug directory itself).
   140  	SizeOfData uint32 `json:"size_of_data"`
   141  
   142  	//The address of the debug data when loaded, relative to the image base.
   143  	AddressOfRawData uint32 `json:"address_of_raw_data"`
   144  
   145  	// The file pointer to the debug data.
   146  	PointerToRawData uint32 `json:"pointer_to_raw_data"`
   147  }
   148  
   149  // DebugEntry wraps ImageDebugDirectory to include debug directory type.
   150  type DebugEntry struct {
   151  	// Points to the image debug entry structure.
   152  	Struct ImageDebugDirectory `json:"struct"`
   153  
   154  	// Holds specific information about the debug type entry.
   155  	Info interface{} `json:"info"`
   156  
   157  	// Type of the debug entry.
   158  	Type string `json:"type"`
   159  }
   160  
   161  // GUID is a 128-bit value consisting of one group of 8 hexadecimal digits,
   162  // followed by three groups of 4 hexadecimal digits each, followed by one
   163  // group of 12 hexadecimal digits.
   164  type GUID struct {
   165  	Data1 uint32
   166  	Data2 uint16
   167  	Data3 uint16
   168  	Data4 [8]byte
   169  }
   170  
   171  // CVSignature represents a CodeView signature.
   172  type CVSignature uint32
   173  
   174  // CVInfoPDB70 represents the the CodeView data block of a PDB 7.0 file.
   175  type CVInfoPDB70 struct {
   176  	// CodeView signature, equal to `RSDS`.
   177  	CVSignature CVSignature `json:"cv_signature"`
   178  
   179  	// A unique identifier, which changes with every rebuild of the executable and PDB file.
   180  	Signature GUID `json:"signature"`
   181  
   182  	// Ever-incrementing value, which is initially set to 1 and incremented every
   183  	// time when a part of the PDB file is updated without rewriting the whole file.
   184  	Age uint32 `json:"age"`
   185  
   186  	// Null-terminated name of the PDB file. It can also contain full or partial
   187  	// path to the file.
   188  	PDBFileName string `json:"pdb_file_name"`
   189  }
   190  
   191  // CVHeader represents the the CodeView header struct to the PDB 2.0 file.
   192  type CVHeader struct {
   193  	// CodeView signature, equal to `NB10`.
   194  	Signature CVSignature `json:"signature"`
   195  
   196  	// CodeView offset. Set to 0, because debug information is stored in a
   197  	// separate file.
   198  	Offset uint32 `json:"offset"`
   199  }
   200  
   201  // CVInfoPDB20 represents the the CodeView data block of a PDB 2.0 file.
   202  type CVInfoPDB20 struct {
   203  	// Points to the CodeView header structure.
   204  	CVHeader CVHeader `json:"cv_header"`
   205  
   206  	// The time when debug information was created (in seconds since 01.01.1970).
   207  	Signature uint32 `json:"signature"`
   208  
   209  	// Ever-incrementing value, which is initially set to 1 and incremented every
   210  	// time when a part of the PDB file is updated without rewriting the whole file.
   211  	Age uint32 `json:"age"`
   212  
   213  	// Null-terminated name of the PDB file. It can also contain full or partial
   214  	// path to the file.
   215  	PDBFileName string `json:"pdb_file_name"`
   216  }
   217  
   218  // FPOFrameType represents the type of a FPO frame.
   219  type FPOFrameType uint8
   220  
   221  // FPOData represents the stack frame layout for a function on an x86 computer when
   222  // frame pointer omission (FPO) optimization is used. The structure is used to locate
   223  // the base of the call frame.
   224  type FPOData struct {
   225  	// The offset of the first byte of the function code.
   226  	OffsetStart uint32 `json:"offset_start"`
   227  
   228  	// The number of bytes in the function.
   229  	ProcSize uint32 `json:"proc_size"`
   230  
   231  	// The number of local variables.
   232  	NumLocals uint32 `json:"num_locals"`
   233  
   234  	// The size of the parameters, in DWORDs.
   235  	ParamsSize uint16 `json:"params_size"`
   236  
   237  	// The number of bytes in the function prolog code.
   238  	PrologLength uint8 `json:"prolog_length"`
   239  
   240  	// The number of registers saved.
   241  	SavedRegsCount uint8 `json:"saved_regs_count"`
   242  
   243  	// A variable that indicates whether the function uses structured exception handling.
   244  	HasSEH uint8 `json:"has_seh"`
   245  
   246  	// A variable that indicates whether the EBP register has been allocated.
   247  	UseBP uint8 `json:"use_bp"`
   248  
   249  	// Reserved for future use.
   250  	Reserved uint8 `json:"reserved"`
   251  
   252  	// A variable that indicates the frame type.
   253  	FrameType FPOFrameType `json:"frame_type"`
   254  }
   255  
   256  // ImagePGOItem represents the _IMAGE_POGO_INFO structure.
   257  type ImagePGOItem struct {
   258  	RVA  uint32 `json:"rva"`
   259  	Size uint32 `json:"size"`
   260  	Name string `json:"name"`
   261  }
   262  
   263  // POGOType represents a POGO type.
   264  type POGOType uint32
   265  
   266  // POGO structure contains information related to the Profile Guided Optimization.
   267  // PGO is an approach to optimization where the compiler uses profile information
   268  // to make better optimization decisions for the program.
   269  type POGO struct {
   270  	// Signature represents the PGO sub type.
   271  	Signature POGOType       `json:"signature"`
   272  	Entries   []ImagePGOItem `json:"entries"`
   273  }
   274  
   275  type VCFeature struct {
   276  	PreVC11 uint32 `json:"pre_vc11"`
   277  	CCpp    uint32 `json:"C/C++"`
   278  	Gs      uint32 `json:"/GS"`
   279  	Sdl     uint32 `json:"/sdl"`
   280  	GuardN  uint32 `json:"guardN"`
   281  }
   282  
   283  type REPRO struct {
   284  	Size uint32 `json:"size"`
   285  	Hash []byte `json:"hash"`
   286  }
   287  
   288  // ImageDebugMisc represents the IMAGE_DEBUG_MISC structure.
   289  type ImageDebugMisc struct {
   290  	// The type of data carried in the `Data` field.
   291  	DataType uint32 `json:"data_type"`
   292  
   293  	// The length of this structure in bytes, including the entire Data field
   294  	// and its NUL terminator (rounded to four byte multiple.)
   295  	Length uint32 `json:"length"`
   296  
   297  	// The encoding of the Data field. True if data is unicode string.
   298  	Unicode bool `json:"unicode"`
   299  
   300  	// Reserved.
   301  	Reserved [3]byte `json:"reserved"`
   302  
   303  	// Actual data.
   304  	Data string `json:"data"`
   305  }
   306  
   307  // Image files contain an optional debug directory that indicates what form of
   308  // debug information is present and where it is. This directory consists of an
   309  // array of debug directory entries whose location and size are indicated in the
   310  // image optional header.  The debug directory can be in a discardable .debug
   311  // section (if one exists), or it can be included in any other section in the
   312  // image file, or not be in a section at all.
   313  func (pe *File) parseDebugDirectory(rva, size uint32) error {
   314  
   315  	debugEntry := DebugEntry{}
   316  	debugDir := ImageDebugDirectory{}
   317  	errorMsg := fmt.Sprintf("Invalid debug information. Can't read data at RVA: 0x%x", rva)
   318  	debugDirSize := uint32(binary.Size(debugDir))
   319  	debugDirsCount := size / debugDirSize
   320  
   321  	for i := uint32(0); i < debugDirsCount; i++ {
   322  		offset := pe.GetOffsetFromRva(rva + debugDirSize*i)
   323  		err := pe.structUnpack(&debugDir, offset, debugDirSize)
   324  		if err != nil {
   325  			return errors.New(errorMsg)
   326  		}
   327  
   328  		switch debugDir.Type {
   329  		case ImageDebugTypeCodeView:
   330  			debugSignature, err := pe.ReadUint32(debugDir.PointerToRawData)
   331  			if err != nil {
   332  				continue
   333  			}
   334  
   335  			if debugSignature == CVSignatureRSDS {
   336  				// PDB 7.0
   337  				pdb := CVInfoPDB70{CVSignature: CVSignatureRSDS}
   338  
   339  				// Extract the GUID.
   340  				offset := debugDir.PointerToRawData + 4
   341  				guidSize := uint32(binary.Size(pdb.Signature))
   342  				err = pe.structUnpack(&pdb.Signature, offset, guidSize)
   343  				if err != nil {
   344  					continue
   345  				}
   346  
   347  				// Extract the age.
   348  				offset += guidSize
   349  				pdb.Age, err = pe.ReadUint32(offset)
   350  				if err != nil {
   351  					continue
   352  				}
   353  				offset += 4
   354  
   355  				// PDB file name.
   356  				pdbFilenameSize := debugDir.SizeOfData - 24 - 1
   357  
   358  				// pdbFileName_size can be negative here, as seen in the malware
   359  				// sample with MD5 hash: 7c297600870d026c014d42596bb9b5fd
   360  				// Checking for positive size here to ensure proper parsing.
   361  				if pdbFilenameSize > 0 {
   362  					pdbFilename := make([]byte, pdbFilenameSize)
   363  					err = pe.structUnpack(&pdbFilename, offset, pdbFilenameSize)
   364  					if err != nil {
   365  						continue
   366  					}
   367  					pdb.PDBFileName = string(pdbFilename)
   368  				}
   369  
   370  				// Include these extra information.
   371  				debugEntry.Info = pdb
   372  
   373  			} else if debugSignature == CVSignatureNB10 {
   374  				// PDB 2.0.
   375  				cvHeader := CVHeader{}
   376  				offset := debugDir.PointerToRawData
   377  				err = pe.structUnpack(&cvHeader, offset, size)
   378  				if err != nil {
   379  					continue
   380  				}
   381  
   382  				pdb := CVInfoPDB20{CVHeader: cvHeader}
   383  
   384  				// Extract the signature.
   385  				pdb.Signature, err = pe.ReadUint32(offset + 8)
   386  				if err != nil {
   387  					continue
   388  				}
   389  
   390  				// Extract the age.
   391  				pdb.Age, err = pe.ReadUint32(offset + 12)
   392  				if err != nil {
   393  					continue
   394  				}
   395  				offset += 16
   396  
   397  				pdbFilenameSize := debugDir.SizeOfData - 16 - 1
   398  				if pdbFilenameSize > 0 {
   399  					pdbFilename := make([]byte, pdbFilenameSize)
   400  					err = pe.structUnpack(&pdbFilename, offset, pdbFilenameSize)
   401  					if err != nil {
   402  						continue
   403  					}
   404  					pdb.PDBFileName = string(pdbFilename)
   405  				}
   406  
   407  				// Include these extra information.
   408  				debugEntry.Info = pdb
   409  			}
   410  		case ImageDebugTypePOGO:
   411  			pogoSignature, err := pe.ReadUint32(debugDir.PointerToRawData)
   412  			if err != nil {
   413  				continue
   414  			}
   415  
   416  			pogo := POGO{}
   417  
   418  			switch pogoSignature {
   419  			case 0x0, POGOTypePGU, POGOTypePGI, POGOTypePGO, POGOTypeLTCG:
   420  				// TODO: Some files like 00da1a2a9d9ebf447508bf6550f05f466f8eabb4ed6c4f2a524c0769b2d75bc1
   421  				// have a POGO signature of 0x0. To be reverse engineered.
   422  				pogo.Signature = POGOType(pogoSignature)
   423  				offset = debugDir.PointerToRawData + 4
   424  				c := uint32(0)
   425  				for c < debugDir.SizeOfData-4 {
   426  
   427  					pogoEntry := ImagePGOItem{}
   428  					pogoEntry.RVA, err = pe.ReadUint32(offset)
   429  					if err != nil {
   430  						break
   431  					}
   432  					offset += 4
   433  
   434  					pogoEntry.Size, err = pe.ReadUint32(offset)
   435  					if err != nil {
   436  						break
   437  					}
   438  					offset += 4
   439  
   440  					pogoEntry.Name = string(pe.GetStringFromData(0, pe.data[offset:offset+64]))
   441  
   442  					pogo.Entries = append(pogo.Entries, pogoEntry)
   443  					offset += uint32(len(pogoEntry.Name))
   444  
   445  					// Make sure offset is aligned to 4 bytes.
   446  					padding := 4 - (offset % 4)
   447  					c += 4 + 4 + uint32(len(pogoEntry.Name)) + padding
   448  					offset += padding
   449  				}
   450  
   451  				debugEntry.Info = pogo
   452  			}
   453  		case ImageDebugTypeVCFeature:
   454  			vcf := VCFeature{}
   455  			size := uint32(binary.Size(vcf))
   456  			err := pe.structUnpack(&vcf, debugDir.PointerToRawData, size)
   457  			if err != nil {
   458  				continue
   459  			}
   460  			debugEntry.Info = vcf
   461  		case ImageDebugTypeRepro:
   462  			repro := REPRO{}
   463  			offset := debugDir.PointerToRawData
   464  
   465  			// Extract the size.
   466  			repro.Size, err = pe.ReadUint32(offset)
   467  			if err != nil {
   468  				continue
   469  			}
   470  
   471  			// Extract the hash.
   472  			repro.Hash, err = pe.ReadBytesAtOffset(offset+4, repro.Size)
   473  			if err != nil {
   474  				continue
   475  			}
   476  			debugEntry.Info = repro
   477  		case ImageDebugTypeFPO:
   478  			offset := debugDir.PointerToRawData
   479  			size := uint32(16)
   480  			fpoEntries := []FPOData{}
   481  			c := uint32(0)
   482  			for c < debugDir.SizeOfData {
   483  				fpo := FPOData{}
   484  				fpo.OffsetStart, err = pe.ReadUint32(offset)
   485  				if err != nil {
   486  					break
   487  				}
   488  
   489  				fpo.ProcSize, err = pe.ReadUint32(offset + 4)
   490  				if err != nil {
   491  					break
   492  				}
   493  
   494  				fpo.NumLocals, err = pe.ReadUint32(offset + 8)
   495  				if err != nil {
   496  					break
   497  				}
   498  
   499  				fpo.ParamsSize, err = pe.ReadUint16(offset + 12)
   500  				if err != nil {
   501  					break
   502  				}
   503  
   504  				fpo.PrologLength, err = pe.ReadUint8(offset + 14)
   505  				if err != nil {
   506  					break
   507  				}
   508  
   509  				attributes, err := pe.ReadUint16(offset + 15)
   510  				if err != nil {
   511  					break
   512  				}
   513  
   514  				//
   515  				// UChar  cbRegs :3;  /* # regs saved */
   516  				// UChar  fHasSEH:1;  /* Structured Exception Handling */
   517  				// UChar  fUseBP :1;  /* EBP has been used */
   518  				// UChar  reserved:1;
   519  				// UChar  cbFrame:2;  /* frame type */
   520  				//
   521  
   522  				// The lowest 3 bits
   523  				fpo.SavedRegsCount = uint8(attributes & 0x7)
   524  
   525  				// The next bit.
   526  				fpo.HasSEH = uint8(attributes & 0x8 >> 3)
   527  
   528  				// The next bit.
   529  				fpo.UseBP = uint8(attributes & 0x10 >> 4)
   530  
   531  				// The next bit.
   532  				fpo.Reserved = uint8(attributes & 0x20 >> 5)
   533  
   534  				// The next 2 bits.
   535  				fpo.FrameType = FPOFrameType(attributes & 0xC0 >> 6)
   536  
   537  				fpoEntries = append(fpoEntries, fpo)
   538  				c += size
   539  				offset += 16
   540  			}
   541  			debugEntry.Info = fpoEntries
   542  		case ImageDebugTypeExDllCharacteristics:
   543  			exDllChar, err := pe.ReadUint32(debugDir.PointerToRawData)
   544  			if err != nil {
   545  				continue
   546  			}
   547  
   548  			debugEntry.Info = DllCharacteristicsExType(exDllChar)
   549  		}
   550  
   551  		debugEntry.Struct = debugDir
   552  		debugEntry.Type = debugDir.Type.String()
   553  		pe.Debugs = append(pe.Debugs, debugEntry)
   554  	}
   555  
   556  	if len(pe.Debugs) > 0 {
   557  		pe.HasDebug = true
   558  	}
   559  
   560  	return nil
   561  }
   562  
   563  // SectionAttributeDescription maps a section attribute to a friendly name.
   564  func SectionAttributeDescription(section string) string {
   565  	sectionNameMap := map[string]string{
   566  		".00cfg":                               "CFG Check Functions Pointers",
   567  		".bss$00":                              "Uninit.data in phaseN of Pri7",
   568  		".bss$dk00":                            "PGI: Uninit.data may be not const",
   569  		".bss$dk01":                            "PGI: Uninit.data may be not const",
   570  		".bss$pr00":                            "PGI: Uninit.data only for read",
   571  		".bss$pr03":                            "PGI: Uninit.data only for read",
   572  		".bss$zz":                              "PGO: Dead uninit.data",
   573  		".CRT$XCA":                             "First C++ Initializer",
   574  		".CRT$XCZ":                             "Last C++ Initializer",
   575  		".xdata$x":                             "EH data",
   576  		".gfids$y":                             "CFG Functions table",
   577  		".CRT$XCAA":                            "Startup C++ Initializer",
   578  		".CRT$XCC":                             "Global initializer: init_seg(compiler)",
   579  		".CRT$XCL":                             "Global initializer: init_seg(lib)",
   580  		".CRT$XCU":                             "Global initializer: init_seg(user)",
   581  		".CRT$XDA":                             "First Dynamic TLS Initializer",
   582  		".CRT$XDZ":                             "Last Dynamic TLS Initializer",
   583  		".CRT$XIA":                             "First C Initializer",
   584  		".CRT$XIAA":                            "Startup C Initializer",
   585  		".CRT$XIAB":                            "PGO C Initializer",
   586  		".CRT$XIAC":                            "Post-PGO C Initializer",
   587  		".CRT$XIC":                             "CRT C Initializers",
   588  		".CRT$XIYA":                            "VCCorLib Threading Model Initializer",
   589  		".CRT$XIYAA":                           "XAML Designer Threading Model Override Initializer",
   590  		".CRT$XIYB":                            "VCCorLib Main Initializer",
   591  		".CRT$XIZ":                             "Last C Initializer",
   592  		".CRT$XLA":                             "First Loader TLS Callback",
   593  		".CRT$XLC":                             "CRT TLS Constructor",
   594  		".CRT$XLD":                             "CRT TLS Terminator",
   595  		".CRT$XLZ":                             "Last Loader TLS Callback",
   596  		".CRT$XPA":                             "First Pre-Terminator",
   597  		".CRT$XPB":                             "CRT ConcRT Pre-Terminator",
   598  		".CRT$XPX":                             "CRT Pre-Terminators",
   599  		".CRT$XPXA":                            "CRT stdio Pre-Terminator",
   600  		".CRT$XPZ":                             "Last Pre-Terminator",
   601  		".CRT$XTA":                             "First Terminator",
   602  		".CRT$XTZ":                             "Last Terminator",
   603  		".CRTMA$XCA":                           "First Managed C++ Initializer",
   604  		".CRTMA$XCZ":                           "Last Managed C++ Initializer",
   605  		".CRTVT$XCA":                           "First Managed VTable Initializer",
   606  		".CRTVT$XCZ":                           "Last Managed VTable Initializer",
   607  		".data$00":                             "Init.data in phaseN of Pri7",
   608  		".data$dk00":                           "PGI: Init.data may be not const",
   609  		".data$dk00$brc":                       "PGI: Init.data may be not const",
   610  		".data$pr00":                           "PGI: Init.data only for read",
   611  		".data$r":                              "RTTI Type Descriptors",
   612  		".data$zz":                             "PGO: Dead init.data",
   613  		".data$zz$brc":                         "PGO: Dead init.data",
   614  		".didat$2":                             "Delay Import Descriptors",
   615  		".didat$3":                             "Delay Import Final NULL Entry",
   616  		".didat$4":                             "Delay Import INT",
   617  		".didat$5":                             "Delay Import IAT",
   618  		".didat$6":                             "Delay Import Symbol Names",
   619  		".didat$7":                             "Delay Import Bound IAT",
   620  		".edata":                               "Export Table",
   621  		".gehcont":                             "CFG EHCont Table",
   622  		".gfids":                               "CFG Functions Table",
   623  		".giats":                               "CFG IAT Table",
   624  		".idata$2":                             "Import Descriptors",
   625  		".idata$3":                             "Import Final NULL Entry",
   626  		".idata$4":                             "Import Names Table",
   627  		".idata$5":                             "Import Addresses Table",
   628  		".idata$6":                             "Import Symbol and DLL Names",
   629  		".pdata":                               "Procedure data",
   630  		".rdata$00":                            "Readonly data in phaseN of Pri7",
   631  		".rdata$00$brc":                        "Readonly data in phaseN of Pri7",
   632  		".rdata$09":                            "Readonly data in phaseN of Pri7",
   633  		".rdata$brc":                           "BaseRelocation Clustering",
   634  		".rdata$r":                             "RTTI Data",
   635  		".rdata$sxdata":                        "Safe SEH",
   636  		".rdata$T":                             "TLS Header",
   637  		".rdata$zETW0":                         "ETW Metadata Header",
   638  		".rdata$zETW1":                         "ETW Events Metadata",
   639  		".rdata$zETW2":                         "ETW Providers Metadata",
   640  		".rdata$zETW9":                         "ETW Metadata Footer",
   641  		".rdata$zz":                            "PGO: Dead Readonly Data",
   642  		".rdata$zz$brc":                        "PGO: Dead Readonly Data",
   643  		".rdata$zzzdbg":                        "Debug directory data",
   644  		".rsrc$01":                             "Resources Header",
   645  		".rsrc$02":                             "Resources Data",
   646  		".rtc$IAA":                             "First RTC Initializer",
   647  		".rtc$IZZ":                             "Last RTC Initializer",
   648  		".rtc$TAA":                             "First RTC Terminator",
   649  		".rtc$TZZ":                             "Last RTC Terminator",
   650  		".text$di":                             "MSVC Dynamic Initializers",
   651  		".text$lp00kernel32.dll!20_pri7":       "PGO: LoaderPhaseN warm-to-hot code",
   652  		".text$lp01kernel32.dll!20_pri7":       "PGO: LoaderPhaseN warm-to-hot code",
   653  		".text$lp03kernel32.dll!30_clientonly": "PGO: LoaderPhaseN warm-to-hot code",
   654  		".text$lp04kernel32.dll!30_clientonly": "PGO: LoaderPhaseN warm-to-hot code",
   655  		".text$lp08kernel32.dll!40_serveronly": "PGO: LoaderPhaseN warm-to-hot code",
   656  		".text$lp09kernel32.dll!40_serveronly": "PGO: LoaderPhaseN warm-to-hot code",
   657  		".text$lp10kernel32.dll!40_serveronly": "PGO: LoaderPhaseN warm-to-hot code",
   658  		".text$mn":                             "Contains EP",
   659  		".text$mn$00":                          "CFG Dispatching",
   660  		".text$np":                             "PGO: __asm or disabled via pragma",
   661  		".text$x":                              "EH Filters",
   662  		".text$yd":                             "MSVC Destructors",
   663  		".text$zy":                             "PGO: Dead Code Blocks",
   664  		".text$zz":                             "PGO: Dead Whole Functions",
   665  		".xdata":                               "Unwind data",
   666  	}
   667  
   668  	if val, ok := sectionNameMap[section]; ok {
   669  		return val
   670  	}
   671  
   672  	return ""
   673  }
   674  
   675  // String returns a string interpretation of the FPO frame type.
   676  func (ft FPOFrameType) String() string {
   677  	frameTypeMap := map[FPOFrameType]string{
   678  		FrameFPO:    "FPO",
   679  		FrameTrap:   "Trap",
   680  		FrameTSS:    "TSS",
   681  		FrameNonFPO: "Non FPO",
   682  	}
   683  
   684  	v, ok := frameTypeMap[ft]
   685  	if ok {
   686  		return v
   687  	}
   688  
   689  	return "?"
   690  }
   691  
   692  // String returns the string representation of a GUID.
   693  func (g GUID) String() string {
   694  	return fmt.Sprintf("{%06X-%04X-%04X-%04X-%X}", g.Data1, g.Data2, g.Data3, g.Data4[0:2], g.Data4[2:])
   695  }
   696  
   697  // String returns the string representation of a debug entry type.
   698  func (t ImageDebugDirectoryType) String() string {
   699  
   700  	debugTypeMap := map[ImageDebugDirectoryType]string{
   701  		ImageDebugTypeUnknown:              "Unknown",
   702  		ImageDebugTypeCOFF:                 "COFF",
   703  		ImageDebugTypeCodeView:             "CodeView",
   704  		ImageDebugTypeFPO:                  "FPO",
   705  		ImageDebugTypeMisc:                 "Misc",
   706  		ImageDebugTypeException:            "Exception",
   707  		ImageDebugTypeFixup:                "Fixup",
   708  		ImageDebugTypeOMAPToSrc:            "OMAP To Src",
   709  		ImageDebugTypeOMAPFromSrc:          "OMAP From Src",
   710  		ImageDebugTypeBorland:              "Borland",
   711  		ImageDebugTypeReserved:             "Reserved",
   712  		ImageDebugTypeVCFeature:            "VC Feature",
   713  		ImageDebugTypePOGO:                 "POGO",
   714  		ImageDebugTypeILTCG:                "iLTCG",
   715  		ImageDebugTypeMPX:                  "MPX",
   716  		ImageDebugTypeRepro:                "REPRO",
   717  		ImageDebugTypeExDllCharacteristics: "Ex.DLL Characteristics",
   718  	}
   719  
   720  	v, ok := debugTypeMap[t]
   721  	if ok {
   722  		return v
   723  	}
   724  
   725  	return "?"
   726  }
   727  
   728  // String returns a string interpretation of a POGO type.
   729  func (p POGOType) String() string {
   730  	pogoTypeMap := map[POGOType]string{
   731  		POGOTypePGU:  "PGU",
   732  		POGOTypePGI:  "PGI",
   733  		POGOTypePGO:  "PGO",
   734  		POGOTypeLTCG: "LTCG",
   735  	}
   736  
   737  	v, ok := pogoTypeMap[p]
   738  	if ok {
   739  		return v
   740  	}
   741  
   742  	return "?"
   743  }
   744  
   745  // String returns a string interpretation of a CodeView signature.
   746  func (s CVSignature) String() string {
   747  	cvSignatureMap := map[CVSignature]string{
   748  		CVSignatureRSDS: "RSDS",
   749  		CVSignatureNB10: "NB10",
   750  	}
   751  
   752  	v, ok := cvSignatureMap[s]
   753  	if ok {
   754  		return v
   755  	}
   756  
   757  	return "?"
   758  }
   759  
   760  // String returns a string interpretation of Dll Characteristics Ex.
   761  func (flag DllCharacteristicsExType) String() string {
   762  	dllCharacteristicsExTypeMap := map[DllCharacteristicsExType]string{
   763  		ImageDllCharacteristicsExCETCompat: "CET Compatible",
   764  	}
   765  
   766  	v, ok := dllCharacteristicsExTypeMap[flag]
   767  	if ok {
   768  		return v
   769  	}
   770  
   771  	return "?"
   772  }