VirtualBox

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

Last change on this file since 94490 was 93470, checked in by vboxsync, 3 years ago

DbgPlugInDiggers,VMM,Main: Refactored the diggers and related interfaces to work via the VMM function table. Removed non-working tstVBoxDbg (needs proper COM now). bugref:10072

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