3 * DBGPlugInCommonELF - Code Template for dealing with one kind of ELF.
7 * Copyright (C) 2008-2010 Oracle Corporation
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.
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
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
38 * Common ELF module parser.
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.
44 * @returns VBox status code.
46 * @param pVM The VM handle.
47 * @param pszModName The module name.
48 * @param pszFilename The filename. optional.
49 * @param fFlags Flags.
50 * @param pEhdr Pointer to the ELF header.
51 * @param paShdrs Pointer to the section headers. The caller must verify that
52 * the e_shnum member of the ELF header is within the bounds of
53 * this table. The caller should also adjust the section addresses
54 * so these correspond to actual load addresses.
55 * @param paSyms Pointer to the symbol table.
56 * @param cMaxSyms The maximum number of symbols paSyms may hold. This isn't
57 * the exact count, it's just a cap for avoiding SIGSEGVs
58 * and general corruption.
59 * @param pbStrings Pointer to the string table.
60 * @param cbMaxStrings The size of the memory pbStrings points to. This doesn't
61 * have to match the string table size exactly, it's just to
62 * avoid SIGSEGV when a bad string index is encountered.
63 * @param MinAddr Min address to care about.
64 * @param MaxAddr Max address to care about (inclusive). Together
65 * with MinAddr this forms a valid address range for
66 * symbols and sections that we care about. Anything
67 * outside the range is ignored, except when doing
69 * @param uModTag Module tag. Pass 0 if tagging is of no interest.
71 int DBGDiggerCommonParseElfMod(PVM pVM
, const char *pszModName
, const char *pszFilename
, uint32_t fFlags
,
72 Elf_Ehdr
const *pEhdr
, Elf_Shdr
const *paShdrs
,
73 Elf_Sym
const *paSyms
, size_t cMaxSyms
,
74 char const *pbStrings
, size_t cbMaxStrings
,
75 RTGCPTR MinAddr
, RTGCPTR MaxAddr
, uint64_t uModTag
)
77 AssertPtrReturn(pVM
, VERR_INVALID_POINTER
);
78 AssertPtrReturn(pszModName
, VERR_INVALID_POINTER
);
79 AssertPtrReturn(pszFilename
, VERR_INVALID_POINTER
);
80 AssertReturn(!(fFlags
& ~DBG_DIGGER_ELF_MASK
), VERR_INVALID_PARAMETER
);
81 AssertReturn((fFlags
& (DBG_DIGGER_ELF_FUNNY_SHDRS
| DBG_DIGGER_ELF_ADJUST_SYM_VALUE
))
82 != (DBG_DIGGER_ELF_FUNNY_SHDRS
| DBG_DIGGER_ELF_ADJUST_SYM_VALUE
), VERR_INVALID_PARAMETER
);
83 AssertPtrReturn(paShdrs
, VERR_INVALID_POINTER
);
84 AssertPtrReturn(paSyms
, VERR_INVALID_POINTER
);
85 AssertPtrReturn(pbStrings
, VERR_INVALID_POINTER
);
88 * Validate the ELF header.
90 if ( pEhdr
->e_ident
[EI_MAG0
] != ELFMAG0
91 || pEhdr
->e_ident
[EI_MAG1
] != ELFMAG1
92 || pEhdr
->e_ident
[EI_MAG2
] != ELFMAG2
93 || pEhdr
->e_ident
[EI_MAG3
] != ELFMAG3
)
94 return VERR_INVALID_EXE_SIGNATURE
;
95 if (pEhdr
->e_ident
[EI_CLASS
] != MY_ELFCLASS
)
96 return VERR_LDRELF_MACHINE
;
98 if (pEhdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
)
99 return VERR_LDRELF_ODD_ENDIAN
;
100 if (pEhdr
->e_ident
[EI_VERSION
] != EV_CURRENT
)
101 return VERR_LDRELF_VERSION
;
102 if (pEhdr
->e_version
!= EV_CURRENT
)
103 return VERR_LDRELF_VERSION
;
104 if (pEhdr
->e_ehsize
!= sizeof(*pEhdr
))
105 return VERR_BAD_EXE_FORMAT
;
108 if ( pEhdr
->e_machine
!= EM_386
109 && pEhdr
->e_machine
!= EM_486
)
110 return VERR_LDRELF_MACHINE
;
112 if (pEhdr
->e_machine
!= EM_X86_64
)
113 return VERR_LDRELF_MACHINE
;
116 if ( pEhdr
->e_type
!= ET_DYN
117 && pEhdr
->e_type
!= ET_REL
118 && pEhdr
->e_type
!= ET_EXEC
) //??
119 return VERR_BAD_EXE_FORMAT
;
120 if ( pEhdr
->e_phentsize
!= sizeof(Elf_Phdr
)
121 && pEhdr
->e_phentsize
) //??
122 return VERR_BAD_EXE_FORMAT
;
123 if (pEhdr
->e_shentsize
!= sizeof(Elf_Shdr
))
124 return VERR_BAD_EXE_FORMAT
;
125 if (pEhdr
->e_shentsize
!= sizeof(Elf_Shdr
))
126 return VERR_BAD_EXE_FORMAT
;
127 if (ASMMemIsAll8(&pEhdr
->e_ident
[EI_PAD
], EI_NIDENT
- EI_PAD
, 0) != NULL
) //??
128 return VERR_BAD_EXE_FORMAT
;
131 * Validate the section headers, finding the string and symbol table
132 * headers and the load address while at it.
134 uint64_t uLoadAddr
= UINT64_MAX
;
135 const Elf_Shdr
*pSymShdr
= NULL
;
136 const Elf_Shdr
*pStrShdr
= NULL
;
137 for (unsigned iSh
= fFlags
& DBG_DIGGER_ELF_FUNNY_SHDRS
? 1 : 0; iSh
< pEhdr
->e_shnum
; iSh
++)
139 /* Minimal validation. */
140 if (paShdrs
[iSh
].sh_link
>= pEhdr
->e_shnum
)
141 return VERR_BAD_EXE_FORMAT
;
143 /* Is it the symbol table?*/
144 if (paShdrs
[iSh
].sh_type
== SHT_SYMTAB
)
147 return VERR_LDRELF_MULTIPLE_SYMTABS
;
148 pSymShdr
= &paShdrs
[iSh
];
149 if (pSymShdr
->sh_entsize
!= sizeof(Elf32_Sym
))
150 return VERR_BAD_EXE_FORMAT
;
151 pStrShdr
= &paShdrs
[paShdrs
[iSh
].sh_link
];
153 if (uLoadAddr
> paShdrs
[iSh
].sh_addr
)
154 uLoadAddr
= paShdrs
[iSh
].sh_addr
;
158 * Validate the symbol table and determine the max section index
159 * when DBG_DIGGER_ELF_FUNNY_SHDRS is flagged.
161 uint32_t uMaxShIdx
= fFlags
& DBG_DIGGER_ELF_FUNNY_SHDRS
? 0 : pEhdr
->e_shnum
- 1;
162 size_t const cbStrings
= pStrShdr
? pStrShdr
->sh_size
: cbMaxStrings
;
163 size_t const cSyms
= pSymShdr
164 ? RT_MIN(cMaxSyms
, pSymShdr
->sh_size
/ sizeof(Elf_Sym
))
166 for (size_t iSym
= 1; iSym
< cSyms
; iSym
++)
168 if (paSyms
[iSym
].st_name
>= cbStrings
)
169 return VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET
;
170 if (fFlags
& DBG_DIGGER_ELF_FUNNY_SHDRS
)
172 if ( paSyms
[iSym
].st_shndx
> uMaxShIdx
173 && paSyms
[iSym
].st_shndx
< SHN_LORESERVE
)
174 uMaxShIdx
= paSyms
[iSym
].st_shndx
;
176 else if ( paSyms
[iSym
].st_shndx
>= pEhdr
->e_shnum
177 && paSyms
[iSym
].st_shndx
!= SHN_UNDEF
178 && ( paSyms
[iSym
].st_shndx
< SHN_LORESERVE
179 /*|| paSyms[iSym].st_shndx > SHN_HIRESERVE*/
180 || ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_GLOBAL
181 || ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_WEAK
) )
182 return VERR_BAD_EXE_FORMAT
;
184 if (uMaxShIdx
> 4096)
185 return VERR_BAD_EXE_FORMAT
;
189 * The funny ELF section headers on solaris makes this very complicated.
191 uint32_t cSegs
= uMaxShIdx
+ 1;
192 PDBGDIGGERELFSEG paSegs
= (PDBGDIGGERELFSEG
)alloca(sizeof(paSegs
[0]) * cSegs
);
193 for (uint32_t i
= 0; i
< cSegs
; i
++)
195 paSegs
[i
].uLoadAddr
= RTGCPTR_MAX
;
196 paSegs
[i
].uLastAddr
= 0;
197 paSegs
[i
].iSeg
= NIL_RTDBGSEGIDX
;
201 int rc
= RTDbgModCreate(&hMod
, pszModName
, 0 /*cbSeg*/, 0 /*fFlags*/);
204 rc
= RTDbgModSetTag(hMod
, uModTag
); AssertRC(rc
);
206 if (fFlags
& DBG_DIGGER_ELF_FUNNY_SHDRS
)
208 /* Seek out the min and max symbol values for each section. */
209 for (uint32_t iSym
= 1; iSym
< cSyms
; iSym
++)
211 /* Ignore undefined, absolute and weak symbols in this pass,
212 but include local ones as well as nameless. */
213 uint32_t iSh
= paSyms
[iSym
].st_shndx
;
214 if ( iSh
!= SHN_UNDEF
216 && ( ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_GLOBAL
217 || ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_LOCAL
))
219 /* Calc the address and check that it doesn't wrap with the size. */
220 RTGCUINTPTR Address
= paSyms
[iSym
].st_value
;
221 RTGCUINTPTR AddressLast
= Address
+ RT_MAX(paSyms
[iSym
].st_size
, 1) - 1;
222 if (AddressLast
< Address
)
224 if ( Address
< MinAddr
225 || AddressLast
> MaxAddr
)
228 /* update min/max. */
229 if (Address
< paSegs
[iSh
].uLoadAddr
)
230 paSegs
[iSh
].uLoadAddr
= Address
;
231 if (AddressLast
> paSegs
[iSh
].uLastAddr
)
232 paSegs
[iSh
].uLastAddr
= AddressLast
;
236 /* Add the segments and fill in the translation table. */
237 RTGCPTR uRvaNext
= 0;
238 for (unsigned i
= 0; i
< cSegs
; i
++)
239 if (paSegs
[i
].uLastAddr
!= 0)
242 RTStrPrintf(szSeg
, sizeof(szSeg
), "sec%02", i
);
243 RTGCPTR cbSeg
= paSegs
[i
].uLastAddr
- paSegs
[i
].uLoadAddr
+ 1;
244 rc
= RTDbgModSegmentAdd(hMod
, uRvaNext
, cbSeg
, szSeg
, 0 /*fFlags*/, &paSegs
[i
].iSeg
);
247 uRvaNext
+= RT_ALIGN_T(cbSeg
, 32, RTGCPTR
);
252 /* Add the segments and fill in the translation table. */
253 RTGCPTR uRvaNext
= 0;
254 for (unsigned i
= 0; i
< cSegs
; i
++)
255 if (paShdrs
[i
].sh_flags
& SHF_ALLOC
)
258 RTStrPrintf(szSeg
, sizeof(szSeg
), "sec%02", i
);
259 rc
= RTDbgModSegmentAdd(hMod
, paShdrs
[i
].sh_addr
- uLoadAddr
, paShdrs
[i
].sh_size
, szSeg
, 0 /*fFlags*/, &paSegs
[i
].iSeg
);
262 paSegs
[i
].uLoadAddr
= paShdrs
[i
].sh_addr
;
263 paSegs
[i
].uLastAddr
= paShdrs
[i
].sh_addr
+ paShdrs
[i
].sh_size
- 1;
268 RTDbgModRelease(hMod
);
274 * Add all relevant symbols in the module
276 for (uint32_t iSym
= 1; iSym
< cSyms
; iSym
++)
278 /* Undefined symbols are not exports, they are imports. */
279 RTDBGSEGIDX iSeg
= paSyms
[iSym
].st_shndx
;
280 if ( iSeg
!= SHN_UNDEF
281 && ( ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_GLOBAL
282 || ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_LOCAL
283 || ELF_ST_BIND(paSyms
[iSym
].st_info
) == STB_WEAK
))
285 /* Get the symbol name. */
286 if (paSyms
[iSym
].st_name
>= cbMaxStrings
)
288 const char *pszSymbol
= pbStrings
+ paSyms
[iSym
].st_name
;
292 /* Calc the address (value) and size. */
293 RTGCUINTPTR cbSym
= paSyms
[iSym
].st_size
;
294 RTGCUINTPTR offSeg
= paSyms
[iSym
].st_value
;
296 iSeg
= RTDBGSEGIDX_ABS
; /* absolute symbols are not subject to any relocation. */
299 Assert(iSeg
< cSegs
);
300 if (fFlags
& (DBG_DIGGER_ELF_FUNNY_SHDRS
| DBG_DIGGER_ELF_ADJUST_SYM_VALUE
))
301 offSeg
-= paSegs
[iSeg
].uLoadAddr
;
302 iSeg
= paSegs
[iSeg
].iSeg
;
303 if (iSeg
== NIL_RTDBGSEGIDX
)
306 if (offSeg
+ cbSym
< offSeg
)
309 rc
= RTDbgModSymbolAdd(hMod
, pszSymbol
, iSeg
, offSeg
, cbSym
, 0 /*fFlags*/, NULL
);
310 Log(("%02x:%RGv %RGv %s!%s (rc=%Rrc)\n", paSyms
[iSym
].st_shndx
, offSeg
, cbSym
, pszModName
, pszSymbol
, rc
));
312 /*else: silently ignore */
316 * Link it into the address space.
318 RTDBGAS hAs
= DBGFR3AsResolveAndRetain(pVM
, DBGF_AS_KERNEL
);
319 if (hAs
!= NIL_RTDBGAS
)
320 rc
= dbgDiggerCommonLinkElfSegs(hAs
, hMod
, paSegs
, cSegs
);
322 rc
= VERR_INTERNAL_ERROR
;
323 RTDbgModRelease(hMod
);
335 #undef DBGDiggerCommonParseElfMod