VirtualBox

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

Last change on this file since 107589 was 107414, checked in by vboxsync, 13 days ago

Debugger/DBGPlugInCommonELFTmpl.cpp.h: Remove redundant sanity check, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.7 KB
Line 
1/* $Id: DBGPlugInCommonELFTmpl.cpp.h 107414 2025-01-06 14:05:49Z 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 (!ASMMemIsZero(&pEhdr->e_ident[EI_PAD], EI_NIDENT - EI_PAD)) //??
138 return VERR_BAD_EXE_FORMAT;
139
140 /*
141 * Validate the section headers, finding the string and symbol table
142 * headers and the load address while at it.
143 */
144 uint64_t uLoadAddr = UINT64_MAX;
145 const Elf_Shdr *pSymShdr = NULL;
146 const Elf_Shdr *pStrShdr = NULL;
147 for (unsigned iSh = fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS ? 1 : 0; iSh < pEhdr->e_shnum; iSh++)
148 {
149 /* Minimal validation. */
150 if (paShdrs[iSh].sh_link >= pEhdr->e_shnum)
151 return VERR_BAD_EXE_FORMAT;
152
153 /* Is it the symbol table?*/
154 if (paShdrs[iSh].sh_type == SHT_SYMTAB)
155 {
156 if (pSymShdr)
157 return VERR_LDRELF_MULTIPLE_SYMTABS;
158 pSymShdr = &paShdrs[iSh];
159 if (pSymShdr->sh_entsize != sizeof(Elf32_Sym))
160 return VERR_BAD_EXE_FORMAT;
161 pStrShdr = &paShdrs[paShdrs[iSh].sh_link];
162 }
163 if (uLoadAddr > paShdrs[iSh].sh_addr)
164 uLoadAddr = paShdrs[iSh].sh_addr;
165 }
166
167 /*
168 * Validate the symbol table and determine the max section index
169 * when DBG_DIGGER_ELF_FUNNY_SHDRS is flagged.
170 */
171 uint32_t uMaxShIdx = fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS ? 0 : pEhdr->e_shnum - 1;
172 size_t const cbStrings = pStrShdr ? pStrShdr->sh_size : cbMaxStrings;
173 size_t const cSyms = pSymShdr
174 ? RT_MIN(cMaxSyms, pSymShdr->sh_size / sizeof(Elf_Sym))
175 : cMaxSyms;
176 for (size_t iSym = 1; iSym < cSyms; iSym++)
177 {
178 if (paSyms[iSym].st_name >= cbStrings)
179 return VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET;
180 if (fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS)
181 {
182 if ( paSyms[iSym].st_shndx > uMaxShIdx
183 && paSyms[iSym].st_shndx < SHN_LORESERVE)
184 uMaxShIdx = paSyms[iSym].st_shndx;
185 }
186 else if ( paSyms[iSym].st_shndx >= pEhdr->e_shnum
187 && paSyms[iSym].st_shndx != SHN_UNDEF
188 && ( paSyms[iSym].st_shndx < SHN_LORESERVE
189 /*|| paSyms[iSym].st_shndx > SHN_HIRESERVE*/
190 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
191 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_WEAK) )
192 return VERR_BAD_EXE_FORMAT;
193 }
194 if (uMaxShIdx > 4096)
195 return VERR_BAD_EXE_FORMAT;
196
197 /*
198 * Create new module.
199 * The funny ELF section headers on solaris makes this very complicated.
200 */
201 uint32_t cSegs = uMaxShIdx + 1;
202 PDBGDIGGERELFSEG paSegs = (PDBGDIGGERELFSEG)alloca(sizeof(paSegs[0]) * cSegs);
203 for (uint32_t i = 0; i < cSegs; i++)
204 {
205 paSegs[i].uLoadAddr = RTGCPTR_MAX;
206 paSegs[i].uLastAddr = 0;
207 paSegs[i].iSeg = NIL_RTDBGSEGIDX;
208 }
209
210 RTDBGMOD hMod;
211 int rc = RTDbgModCreate(&hMod, pszModName, 0 /*cbSeg*/, 0 /*fFlags*/);
212 if (RT_FAILURE(rc))
213 return rc;
214 rc = RTDbgModSetTag(hMod, uModTag); AssertRC(rc);
215
216 if (fFlags & DBG_DIGGER_ELF_FUNNY_SHDRS)
217 {
218 /* Seek out the min and max symbol values for each section. */
219 for (uint32_t iSym = 1; iSym < cSyms; iSym++)
220 {
221 /* Ignore undefined, absolute and weak symbols in this pass,
222 but include local ones as well as nameless. */
223 uint32_t iSh = paSyms[iSym].st_shndx;
224 if ( iSh != SHN_UNDEF
225 && iSh < cSegs
226 && ( ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
227 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_LOCAL))
228 {
229 /* Calc the address and check that it doesn't wrap with the size. */
230 RTGCUINTPTR Address = paSyms[iSym].st_value;
231 RTGCUINTPTR AddressLast = Address + RT_MAX(paSyms[iSym].st_size, 1) - 1;
232 if (AddressLast < Address)
233 continue;
234 if ( Address < MinAddr
235 || AddressLast > MaxAddr)
236 continue;
237
238 /* update min/max. */
239 if (Address < paSegs[iSh].uLoadAddr)
240 paSegs[iSh].uLoadAddr = Address;
241 if (AddressLast > paSegs[iSh].uLastAddr)
242 paSegs[iSh].uLastAddr = AddressLast;
243 }
244 }
245
246 /* Add the segments and fill in the translation table. */
247 RTGCPTR uRvaNext = 0;
248 for (unsigned i = 0; i < cSegs; i++)
249 if (paSegs[i].uLastAddr != 0)
250 {
251 char szSeg[32];
252 RTStrPrintf(szSeg, sizeof(szSeg), "sec%02u", i);
253 RTGCPTR cbSeg = paSegs[i].uLastAddr - paSegs[i].uLoadAddr + 1;
254 rc = RTDbgModSegmentAdd(hMod, uRvaNext, cbSeg, szSeg, 0 /*fFlags*/, &paSegs[i].iSeg);
255 if (RT_FAILURE(rc))
256 break;
257 uRvaNext += RT_ALIGN_T(cbSeg, 32, RTGCPTR);
258 }
259 }
260 else
261 {
262 /* Add the segments and fill in the translation table. */
263 for (unsigned i = 0; i < cSegs; i++)
264 if (paShdrs[i].sh_flags & SHF_ALLOC)
265 {
266 char szSeg[32];
267 RTStrPrintf(szSeg, sizeof(szSeg), "sec%02u", i);
268 rc = RTDbgModSegmentAdd(hMod, paShdrs[i].sh_addr - uLoadAddr, paShdrs[i].sh_size, szSeg, 0 /*fFlags*/, &paSegs[i].iSeg);
269 if (RT_FAILURE(rc))
270 break;
271 paSegs[i].uLoadAddr = paShdrs[i].sh_addr;
272 paSegs[i].uLastAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size - 1;
273 }
274 }
275 if (RT_FAILURE(rc))
276 {
277 RTDbgModRelease(hMod);
278 return rc;
279 }
280
281
282 /*
283 * Add all relevant symbols in the module
284 */
285 for (uint32_t iSym = 1; iSym < cSyms; iSym++)
286 {
287 /* Undefined symbols are not exports, they are imports. */
288 RTDBGSEGIDX iSeg = paSyms[iSym].st_shndx;
289 if ( iSeg != SHN_UNDEF
290 && ( ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
291 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_LOCAL
292 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_WEAK))
293 {
294 /* Get the symbol name. */
295 if (paSyms[iSym].st_name >= cbMaxStrings)
296 continue;
297 const char *pszSymbol = pbStrings + paSyms[iSym].st_name;
298 if (!*pszSymbol)
299 continue;
300
301 /* Calc the address (value) and size. */
302 RTGCUINTPTR cbSym = paSyms[iSym].st_size;
303 RTGCUINTPTR offSeg = paSyms[iSym].st_value;
304 if (iSeg == SHN_ABS)
305 iSeg = RTDBGSEGIDX_ABS; /* absolute symbols are not subject to any relocation. */
306 else
307 {
308 Assert(iSeg < cSegs);
309 if (fFlags & (DBG_DIGGER_ELF_FUNNY_SHDRS | DBG_DIGGER_ELF_ADJUST_SYM_VALUE))
310 offSeg -= paSegs[iSeg].uLoadAddr;
311 iSeg = paSegs[iSeg].iSeg;
312 if (iSeg == NIL_RTDBGSEGIDX)
313 continue;
314 }
315 if (offSeg + cbSym < offSeg)
316 continue;
317
318 rc = RTDbgModSymbolAdd(hMod, pszSymbol, iSeg, offSeg, cbSym, 0 /*fFlags*/, NULL);
319 if (RT_FAILURE(rc))
320 LogRel(("%02x:%RGv %RGv %s!%s -> rc=%Rrc\n", paSyms[iSym].st_shndx, offSeg, cbSym, pszModName, pszSymbol, rc));
321 Log(("%02x:%RGv %RGv %s!%s (rc=%Rrc)\n", paSyms[iSym].st_shndx, offSeg, cbSym, pszModName, pszSymbol, rc));
322 }
323 /*else: silently ignore */
324 }
325
326 /*
327 * Link it into the address space.
328 */
329 RTDBGAS hAs = pVMM->pfnDBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
330 if (hAs != NIL_RTDBGAS)
331 rc = dbgDiggerCommonLinkElfSegs(hAs, hMod, paSegs, cSegs);
332 else
333 rc = VERR_INTERNAL_ERROR;
334 RTDbgModRelease(hMod);
335 RTDbgAsRelease(hAs);
336 return rc;
337}
338
339
340#undef Elf_Ehdr
341#undef Elf_Shdr
342#undef Elf_Phdr
343#undef Elf_Sym
344#undef MY_ELFCLASS
345#undef ELF_ST_BIND
346#undef DBGDiggerCommonParseElfMod
347
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