summaryrefslogtreecommitdiffstats
path: root/src/PEImage.h
blob: a3e3cd756f088fb2549b8b1dfe7b53d6e66b09cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Convert DMD CodeView debug information to PDB files

// Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved

//

// License for redistribution is given by the Artistic License 2.0

// see file LICENSE for further details


#ifndef __PEIMAGE_H__

#define __PEIMAGE_H__


#include "LastError.h"


#include <windows.h>

#include <unordered_map>


struct OMFDirHeader;
struct OMFDirEntry;

typedef unsigned char byte;

struct SymbolInfo
{
	int seg;
	unsigned long off;
	bool dllimport;
};

struct PESection
{
	byte* base;
	unsigned long length;
	unsigned int secNo;

	PESection()
		: base(0)
		, length(0)
		, secNo(0)
	{
	}

	byte* byteAt(unsigned int off) const
	{
		return base + off;
	}

	byte* startByte() const
	{
		return byteAt(0);
	}

	byte* endByte() const
	{
		return byteAt(0) + length;
	}

	bool isPresent() const
	{
		return base && length;
	}

	bool isPtrInside(const void *p) const
	{
		auto pInt = (uintptr_t)p;
		return (pInt >= (uintptr_t)base && pInt < (uintptr_t)base + length);
	}

	unsigned int sectOff(void *p) const
	{
		return (unsigned int)((uintptr_t)p - (uintptr_t)base);
	}
};

// Define the list of interesting PE sections in one place so that we can

// generate definitions needed to populate our pointers and reference each

// section.


#define SECTION_LIST() \

	EXPANDSEC(debug_addr) \
	EXPANDSEC(debug_info) \
	EXPANDSEC(debug_abbrev) \
	EXPANDSEC(debug_line) \
	EXPANDSEC(debug_line_str) \
	EXPANDSEC(debug_frame) \
	EXPANDSEC(debug_str) \
	EXPANDSEC(debug_str_offsets) \
	EXPANDSEC(debug_loc) \
	EXPANDSEC(debug_loclists) \
	EXPANDSEC(debug_ranges) \
	EXPANDSEC(debug_rnglists) \
	EXPANDSEC(reloc) \
	EXPANDSEC(text)


#define IMGHDR(x) (hdr32 ? hdr32->x : hdr64->x)


class PEImage : public LastError
{
public:
	PEImage(const TCHAR* iname = 0);
	~PEImage();

	template<class P> P* DP(int off) const
	{
		return (P*) ((char*) dump_base + off);
	}
	template<class P> P* DPV(int off, int size) const
	{
		if(off < 0 || off + size > dump_total_len)
			return 0;
		return (P*) ((char*) dump_base + off);
	}
	template<class P> P* DPV(int off) const
	{
		return DPV<P>(off, sizeof(P));
	}
	template<class P> P* CVP(int off) const
	{
		return DPV<P>(cv_base + off, sizeof(P));
	}

	template<class P> P* RVA(unsigned long rva, int len)
	{
		IMAGE_DOS_HEADER *dos = DPV<IMAGE_DOS_HEADER> (0);
		IMAGE_NT_HEADERS32* hdr = DPV<IMAGE_NT_HEADERS32> (dos->e_lfanew);
		IMAGE_SECTION_HEADER* sec = IMAGE_FIRST_SECTION(hdr);

		for (int i = 0; i < hdr->FileHeader.NumberOfSections; i++)
		{
			if (rva       >= sec[i].VirtualAddress &&
				rva + len <= sec[i].VirtualAddress + sec[i].SizeOfRawData)
				return DPV<P>(sec[i].PointerToRawData + rva - sec[i].VirtualAddress, len);
		}
		return 0;
	}

	bool readAll(const TCHAR* iname);
	bool loadExe(const TCHAR* iname);
	bool loadObj(const TCHAR* iname);
	bool save(const TCHAR* oname);

	bool replaceDebugSection (const void* data, int datalen, bool initCV);
	void initSec(PESection& peSec, int secNo) const;
	bool initCVPtr(bool initDbgDir);
	bool initDbgPtr(bool initDbgDir);
	bool initDWARFPtr(bool initDbgDir);
    bool initDWARFObject();
    void initDWARFSegments();
	bool relocateDebugLineInfo(unsigned int img_base);

	bool hasDWARF() const { return debug_line.isPresent(); }
	bool isX64() const { return x64; }
	bool isDBG() const { return dbgfile; }

	int countCVEntries() const;
	OMFDirEntry* getCVEntry(int i) const;

	int getCVSize() const { return dbgDir->SizeOfData; }

	// utilities

	static void* alloc_aligned(unsigned int size, unsigned int align, unsigned int alignoff = 0);
	static void free_aligned(void* p);

	int countSections() const { return nsec; }
	int findSection(unsigned int off) const;
	int findSymbol(const char* name, unsigned long& off, bool& dllimport) const;
	const char* findSectionSymbolName(int s) const;
	const IMAGE_SECTION_HEADER& getSection(int s) const { return sec[s]; }
	unsigned long long getImageBase() const { return IMGHDR(OptionalHeader.ImageBase); }
    int getRelocationInLineSegment(unsigned int offset) const;
    int getRelocationInSegment(int segment, unsigned int offset) const;

    int dumpDebugLineInfoCOFF();
    int dumpDebugLineInfoOMF();
	void createSymbolCache();

private:
	bool _initFromCVDebugDir(IMAGE_DEBUG_DIRECTORY* ddir);

    template<typename SYM> const char* t_findSectionSymbolName(int s) const;

	int fd;
	void* dump_base;
	int dump_total_len;

	// codeview

	IMAGE_DOS_HEADER *dos;
	IMAGE_NT_HEADERS32* hdr32;
	IMAGE_NT_HEADERS64* hdr64;
	IMAGE_SECTION_HEADER* sec;
	IMAGE_DEBUG_DIRECTORY* dbgDir;
	OMFDirHeader* dirHeader;
	OMFDirEntry* dirEntry;
	int nsec;
	int nsym;
	const char* symtable;
	const char* strtable;
	bool x64;     // targets 64-bit machine

	bool bigobj;
	bool dbgfile; // is DBG file

	std::unordered_map<std::string, SymbolInfo> symbolCache;

public:
	//dwarf

#define EXPANDSEC(name) PESection name;

	SECTION_LIST()
#undef EXPANDSEC


	int cv_base;
};

struct SectionDescriptor {
	const char *name;
	PESection PEImage::* pSec;
};

#define EXPANDSEC(name) constexpr SectionDescriptor sec_desc_##name { "." #name, &PEImage::name };

SECTION_LIST()
#undef EXPANDSEC


constexpr const SectionDescriptor *sec_descriptors[] =
{
#define EXPANDSEC(name) &sec_desc_##name,

	SECTION_LIST()
#undef EXPANDSEC

};


#undef SECTION_LIST


#endif //__PEIMAGE_H__