VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGPlugInCommonELFTmpl.cpp.h@ 31510

Last change on this file since 31510 was 31510, checked in by vboxsync, 14 years ago

The debugger is back in the OSE.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.8 KB
Line 
1/* $Id: DBGPlugInCommonELFTmpl.cpp.h 31510 2010-08-10 08:48:11Z vboxsync $ */
2/** @file
3 * DBGPlugInCommonELF - Code Template for dealing with one kind of ELF.
4 */
5
6/*
7 * Copyright (C) 2008-2009 Oracle Corporation
8 *
9 * Oracle Corporation confidential
10 * All rights reserved
11 */
12
13#if ELF_MODE == 32
14# define Elf_Ehdr Elf32_Ehdr
15# define Elf_Shdr Elf32_Shdr
16# define Elf_Phdr Elf32_Phdr
17# define Elf_Sym Elf32_Sym
18# define MY_ELFCLASS ELFCLASS32
19# define ELF_ST_BIND ELF32_ST_BIND
20# define DBGDiggerCommonParseElfMod DBGDiggerCommonParseElf32Mod
21#else
22# define Elf_Ehdr Elf64_Ehdr
23# define Elf_Shdr Elf64_Shdr
24# define Elf_Phdr Elf64_Phdr
25# define Elf_Sym Elf64_Sym
26# define MY_ELFCLASS ELFCLASS64
27# define ELF_ST_BIND ELF64_ST_BIND
28# define DBGDiggerCommonParseElfMod DBGDiggerCommonParseElf64Mod
29#endif
30
31
32/**
33 * Common ELF module parser.
34 *
35 * It takes the essential bits of the ELF module (elf header, section headers,
36 * symbol table and string table), and inserts/updates the module and symbols.
37 *
38 *
39 * @returns VBox status code.
40 *
41 * @param pVM The VM handle.
42 * @param pszModName The module name.
43 * @param pszFilename The filename. optional.
44 * @param fFlags Flags.
45 * @param pEhdr Pointer to the ELF header.
46 * @param paShdrs Pointer to the section headers. The caller must verify that
47 * the e_shnum member of the ELF header is within the bounds of
48 * this table. The caller should also adjust the section addresses
49 * so these correspond to actual load addresses.
50 * @param paSyms Pointer to the symbol table.
51 * @param cMaxSyms The maximum number of symbols paSyms may hold. This isn't
52 * the exact count, it's just a cap for avoiding SIGSEGVs
53 * and general corruption.
54 * @param pbStrings Pointer to the string table.
55 * @param cbMaxStrings The size of the memory pbStrings points to. This doesn't
56 * have to match the string table size exactly, it's just to
57 * avoid SIGSEGV when a bad string index is encountered.
58 * @param MinAddr Min address to care about.
59 * @param MaxAddr Max address to care about (inclusive). Together
60 * with MinAddr this forms a valid address range for
61 * symbols and sections that we care about. Anything
62 * outside the range is ignored, except when doing
63 * sanity checks..
64 * @param uModTag Module tag. Pass 0 if tagging is of no interest.
65 */
66int DBGDiggerCommonParseElfMod(PVM pVM, const char *pszModName, const char *pszFilename, uint32_t fFlags,
67 Elf_Ehdr const *pEhdr, Elf_Shdr const *paShdrs,
68 Elf_Sym const *paSyms, size_t cMaxSyms,
69 char const *pbStrings, size_t cbMaxStrings,
70 RTGCPTR MinAddr, RTGCPTR MaxAddr, uint64_t uModTag)
71{
72 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
73 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
74 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
75 AssertReturn(!(fFlags & ~DBG_DIGGER_ELF_MASK), VERR_INVALID_PARAMETER);
76 AssertReturn((fFlags & (DBG_DIGGER_ELF_FUNNY_SHDRS | DBG_DIGGER_ELF_ADJUST_SYM_VALUE))
77 != (DBG_DIGGER_ELF_FUNNY_SHDRS | DBG_DIGGER_ELF_ADJUST_SYM_VALUE), VERR_INVALID_PARAMETER);
78 AssertPtrReturn(paShdrs, VERR_INVALID_POINTER);
79 AssertPtrReturn(paSyms, VERR_INVALID_POINTER);
80 AssertPtrReturn(pbStrings, VERR_INVALID_POINTER);
81
82 /*
83 * Validate the ELF header.
84 */
85 if ( pEhdr->e_ident[EI_MAG0] != ELFMAG0
86 || pEhdr->e_ident[EI_MAG1] != ELFMAG1
87 || pEhdr->e_ident[EI_MAG2] != ELFMAG2
88 || pEhdr->e_ident[EI_MAG3] != ELFMAG3)
89 return VERR_INVALID_EXE_SIGNATURE;
90 if (pEhdr->e_ident[EI_CLASS] != MY_ELFCLASS)
91 return VERR_LDRELF_MACHINE;
92
93 if (pEhdr->e_ident[EI_DATA] != ELFDATA2LSB)
94 return VERR_LDRELF_ODD_ENDIAN;
95 if (pEhdr->e_ident[EI_VERSION] != EV_CURRENT)
96 return VERR_LDRELF_VERSION;
97 if (pEhdr->e_version != EV_CURRENT)
98 return VERR_LDRELF_VERSION;
99 if (pEhdr->e_ehsize != sizeof(*pEhdr))
100 return VERR_BAD_EXE_FORMAT;
101
102#if ELF_MODE == 32
103 if ( pEhdr->e_machine != EM_386
104 && pEhdr->e_machine != EM_486)
105 return VERR_LDRELF_MACHINE;
106#else
107 if (pEhdr->e_machine != EM_X86_64)
108 return VERR_LDRELF_MACHINE;
109#endif
110
111 if ( pEhdr->e_type != ET_DYN
112 && pEhdr->e_type != ET_REL
113 && pEhdr->e_type != ET_EXEC) //??
114 return VERR_BAD_EXE_FORMAT;
115 if ( pEhdr->e_phentsize != sizeof(Elf_Phdr)
116 && pEhdr->e_phentsize) //??
117 return VERR_BAD_EXE_FORMAT;
118 if (pEhdr->e_shentsize != sizeof(Elf_Shdr))
119 return VERR_BAD_EXE_FORMAT;
120 if (pEhdr->e_shentsize != sizeof(Elf_Shdr))
121 return VERR_BAD_EXE_FORMAT;
122 if (ASMMemIsAll8(&pEhdr->e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0) != NULL) //??
123 return VERR_BAD_EXE_FORMAT;
124
125 /*
126 * Validate the section headers, finding the string and symbol table
127 * headers and the load address while at it.
128 */
129 uint64_t uLoadAddr = UINT64_MAX;
130 const Elf_Shdr *pSymShdr = NULL;
131 const Elf_Shdr *pStrShdr = NULL;
132 for (unsigned iSh = fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS ? 1 : 0; iSh < pEhdr->e_shnum; iSh++)
133 {
134 /* Minimal validation. */
135 if (paShdrs[iSh].sh_link >= pEhdr->e_shnum)
136 return VERR_BAD_EXE_FORMAT;
137
138 /* Is it the symbol table?*/
139 if (paShdrs[iSh].sh_type == SHT_SYMTAB)
140 {
141 if (pSymShdr)
142 return VERR_LDRELF_MULTIPLE_SYMTABS;
143 pSymShdr = &paShdrs[iSh];
144 if (pSymShdr->sh_entsize != sizeof(Elf32_Sym))
145 return VERR_BAD_EXE_FORMAT;
146 pStrShdr = &paShdrs[paShdrs[iSh].sh_link];
147 }
148 if (uLoadAddr > paShdrs[iSh].sh_addr)
149 uLoadAddr = paShdrs[iSh].sh_addr;
150 }
151
152 /*
153 * Validate the symbol table and determin the max section index
154 * when DBG_DIGGER_ELF_FUNNY_SHDRS is flagged.
155 */
156 uint32_t uMaxShIdx = fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS ? 0 : pEhdr->e_shnum - 1;
157 size_t const cbStrings = pStrShdr ? pStrShdr->sh_size : cbMaxStrings;
158 size_t const cSyms = pSymShdr
159 ? RT_MIN(cMaxSyms, pSymShdr->sh_size / sizeof(Elf_Sym))
160 : cMaxSyms;
161 for (size_t iSym = 1; iSym < cSyms; iSym++)
162 {
163 if (paSyms[iSym].st_name >= cbStrings)
164 return VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET;
165 if (fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS)
166 {
167 if ( paSyms[iSym].st_shndx > uMaxShIdx
168 && paSyms[iSym].st_shndx < SHN_LORESERVE)
169 uMaxShIdx = paSyms[iSym].st_shndx;
170 }
171 else if ( paSyms[iSym].st_shndx >= pEhdr->e_shnum
172 && paSyms[iSym].st_shndx != SHN_UNDEF
173 && ( paSyms[iSym].st_shndx < SHN_LORESERVE
174 /*|| paSyms[iSym].st_shndx > SHN_HIRESERVE*/
175 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
176 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_WEAK) )
177 return VERR_BAD_EXE_FORMAT;
178 }
179 if (uMaxShIdx > 4096)
180 return VERR_BAD_EXE_FORMAT;
181
182 /*
183 * Create new module.
184 * The funny ELF section headers on solaris makes this very complicated.
185 */
186 uint32_t cSegs = uMaxShIdx + 1;
187 PDBGDIGGERELFSEG paSegs = (PDBGDIGGERELFSEG)alloca(sizeof(paSegs[0]) * cSegs);
188 for (uint32_t i = 0; i < cSegs; i++)
189 {
190 paSegs[i].uLoadAddr = RTGCPTR_MAX;
191 paSegs[i].uLastAddr = 0;
192 paSegs[i].iSeg = NIL_RTDBGSEGIDX;
193 }
194
195 RTDBGMOD hMod;
196 int rc = RTDbgModCreate(&hMod, pszModName, 0 /*cbSeg*/, 0 /*fFlags*/);
197 if (RT_FAILURE(rc))
198 return rc;
199 rc = RTDbgModSetTag(hMod, uModTag); AssertRC(rc);
200
201 if (fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS)
202 {
203 /* Seek out the min and max symbol values for each section. */
204 for (uint32_t iSym = 1; iSym < cSyms; iSym++)
205 {
206 /* Ignore undefined, absolute and weak symbols in this pass,
207 but include local ones as well as nameless. */
208 uint32_t iSh = paSyms[iSym].st_shndx;
209 if ( iSh != SHN_UNDEF
210 && iSh < cSegs
211 && ( ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
212 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_LOCAL))
213 {
214 /* Calc the address and check that it doesn't wrap with the size. */
215 RTGCUINTPTR Address = paSyms[iSym].st_value;
216 RTGCUINTPTR AddressLast = Address + RT_MAX(paSyms[iSym].st_size, 1) - 1;
217 if (AddressLast < Address)
218 continue;
219 if ( Address < MinAddr
220 || AddressLast > MaxAddr)
221 continue;
222
223 /* update min/max. */
224 if (Address < paSegs[iSh].uLoadAddr)
225 paSegs[iSh].uLoadAddr = Address;
226 if (AddressLast > paSegs[iSh].uLastAddr)
227 paSegs[iSh].uLastAddr = AddressLast;
228 }
229 }
230
231 /* Add the segments and fill in the translation table. */
232 RTGCPTR uRvaNext = 0;
233 for (unsigned i = 0; i < cSegs; i++)
234 if (paSegs[i].uLastAddr != 0)
235 {
236 char szSeg[32];
237 RTStrPrintf(szSeg, sizeof(szSeg), "sec%02", i);
238 RTGCPTR cbSeg = paSegs[i].uLastAddr - paSegs[i].uLoadAddr + 1;
239 rc = RTDbgModSegmentAdd(hMod, uRvaNext, cbSeg, szSeg, 0 /*fFlags*/, &paSegs[i].iSeg);
240 if (RT_FAILURE(rc))
241 break;
242 uRvaNext += RT_ALIGN_T(cbSeg, 32, RTGCPTR);
243 }
244 }
245 else
246 {
247 /* Add the segments and fill in the translation table. */
248 RTGCPTR uRvaNext = 0;
249 for (unsigned i = 0; i < cSegs; i++)
250 if (paShdrs[i].sh_flags & SHF_ALLOC)
251 {
252 char szSeg[32];
253 RTStrPrintf(szSeg, sizeof(szSeg), "sec%02", i);
254 rc = RTDbgModSegmentAdd(hMod, paShdrs[i].sh_addr - uLoadAddr, paShdrs[i].sh_size, szSeg, 0 /*fFlags*/, &paSegs[i].iSeg);
255 if (RT_FAILURE(rc))
256 break;
257 paSegs[i].uLoadAddr = paShdrs[i].sh_addr;
258 paSegs[i].uLastAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size - 1;
259 }
260 }
261 if (RT_FAILURE(rc))
262 {
263 RTDbgModRelease(hMod);
264 return rc;
265 }
266
267
268 /*
269 * Add all relevant symbols in the module
270 */
271 for (uint32_t iSym = 1; iSym < cSyms; iSym++)
272 {
273 /* Undefined symbols are not exports, they are imports. */
274 RTDBGSEGIDX iSeg = paSyms[iSym].st_shndx;
275 if ( iSeg != SHN_UNDEF
276 && ( ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
277 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_LOCAL
278 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_WEAK))
279 {
280 /* Get the symbol name. */
281 if (paSyms[iSym].st_name >= cbMaxStrings)
282 continue;
283 const char *pszSymbol = pbStrings + paSyms[iSym].st_name;
284 if (!*pszSymbol)
285 continue;
286
287 /* Calc the address (value) and size. */
288 RTGCUINTPTR cbSym = paSyms[iSym].st_size;
289 RTGCUINTPTR offSeg = paSyms[iSym].st_value;
290 if (iSeg == SHN_ABS)
291 iSeg = RTDBGSEGIDX_ABS; /* absolute symbols are not subject to any relocation. */
292 else
293 {
294 Assert(iSeg < cSegs);
295 if (fFlags & (DBG_DIGGER_ELF_FUNNY_SHDRS | DBG_DIGGER_ELF_ADJUST_SYM_VALUE))
296 offSeg -= paSegs[iSeg].uLoadAddr;
297 iSeg = paSegs[iSeg].iSeg;
298 if (iSeg == NIL_RTDBGSEGIDX)
299 continue;
300 }
301 if (offSeg + cbSym < offSeg)
302 continue;
303
304 rc = RTDbgModSymbolAdd(hMod, pszSymbol, iSeg, offSeg, cbSym, 0 /*fFlags*/, NULL);
305 Log(("%02x:%RGv %RGv %s!%s (rc=%Rrc)\n", paSyms[iSym].st_shndx, offSeg, cbSym, pszModName, pszSymbol, rc));
306 }
307 /*else: silently ignore */
308 }
309
310 /*
311 * Link it into the address space.
312 */
313 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL);
314 if (hAs != NIL_RTDBGAS)
315 rc = dbgDiggerCommonLinkElfSegs(hAs, hMod, paSegs, cSegs);
316 else
317 rc = VERR_INTERNAL_ERROR;
318 RTDbgModRelease(hMod);
319 RTDbgAsRelease(hAs);
320 return rc;
321}
322
323
324#undef Elf_Ehdr
325#undef Elf_Shdr
326#undef Elf_Phdr
327#undef Elf_Sym
328#undef MY_ELFCLASS
329#undef ELF_ST_BIND
330#undef DBGDiggerCommonParseElfMod
331
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette