VirtualBox

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

Last change on this file since 107044 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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