The Pedigree Project 0.1
DynamicLinker.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "DynamicLinker.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/linker/Elf.h"
24#include "pedigree/kernel/linker/SymbolTable.h"
25#include "pedigree/kernel/process/Mutex.h"
26#include "pedigree/kernel/process/Process.h"
27#include "pedigree/kernel/process/Thread.h"
28#include "pedigree/kernel/processor/KernelCoreSyscallManager.h"
29#include "pedigree/kernel/processor/MemoryRegion.h"
30#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
31#include "pedigree/kernel/processor/Processor.h"
32#include "pedigree/kernel/processor/ProcessorInformation.h"
33#include "pedigree/kernel/processor/VirtualAddressSpace.h"
34#include "pedigree/kernel/processor/state.h"
35#include "pedigree/kernel/syscallError.h"
36#include "pedigree/kernel/utilities/Iterator.h"
37#include "pedigree/kernel/utilities/List.h"
38#include "pedigree/kernel/utilities/Result.h"
39#include "pedigree/kernel/utilities/utility.h"
40
41#include "modules/Module.h"
42#include "modules/system/vfs/File.h"
44#include "modules/system/vfs/Symlink.h"
45#include "modules/system/vfs/VFS.h"
46
47namespace {
48bool prepareNativeImageAllocation() {
49 auto& space = Processor::information().getVirtualAddressSpace();
50 auto* account = space.memoryLockAccount();
51 if (account && account->futureMode() != MemoryLockMode::None) {
52 SYSCALL_ERROR(OperationNotSupported);
53 return false;
54 }
55 // This optional linker owns demand-paged raw ELF extents. The maintained
56 // POSIX loader uses managed mappings with a complete locking inventory.
57 space.rawUserMemory().setCompleteInventory(false);
58 return true;
59}
60
61class DemandPageStagingMapping {
62 public:
63 explicit DemandPageStagingMapping(physical_uintptr_t page)
64 : m_Region("Dynamic Linker Demand Page"), m_Mapped(false) {
66 if (!memory.allocateRegion(
69 return;
70 }
71
73 m_Mapped = kernelSpace.map(page, m_Region.virtualAddress(),
75 if (!m_Mapped) {
76 m_Region.free();
77 }
78 }
79
80 ~DemandPageStagingMapping() {
81 if (m_Mapped) {
82 VirtualAddressSpace::getKernelAddressSpace().unmap(m_Region.virtualAddress());
83 }
84 m_Region.free();
85 }
86
87 bool valid() const {
88 return m_Mapped;
89 }
90
91 uintptr_t address() const {
92 return reinterpret_cast<uintptr_t>(m_Region.virtualAddress());
93 }
94
95 private:
96 NOT_COPYABLE_OR_ASSIGNABLE(DemandPageStagingMapping);
97
98 MemoryRegion m_Region;
99 bool m_Mapped;
100};
101
102Mutex g_DemandPagePublishLock;
103} // namespace
104
105DLTrapHandler DLTrapHandler::m_Instance;
106
107#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS) && \
108 (!defined(PEDIGREE_HOSTED_DARWIN) || !PEDIGREE_HOSTED_DARWIN)
109extern bool runHostedPageContentRegressions();
110#endif
111
112#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS)
113namespace {
114physical_uintptr_t (*g_DemandPageAllocationHook)() = nullptr;
115void (*g_DemandPageReadyHook)(uintptr_t) = nullptr;
116void (*g_DemandPageFreeHook)(physical_uintptr_t) = nullptr;
117} // namespace
118#endif
119
120namespace {
121void releaseDemandPage(physical_uintptr_t page) {
122#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS)
123 if (g_DemandPageFreeHook) {
124 g_DemandPageFreeHook(page);
125 }
126#endif
128}
129} // namespace
130
131uintptr_t DynamicLinker::resolvePlt(SyscallState& state) {
132 Process* pProcess = Processor::information().getCurrentThread()->getParent();
133
134 return pProcess->getLinker()->resolvePltSymbol(state.getSyscallParameter(0),
135 state.getSyscallParameter(1));
136}
137
139 : m_pProgramElf(0),
140 m_ProgramStart(0),
141 m_ProgramSize(0),
142 m_ProgramBuffer(0),
143 m_LoadedObjects(),
144 m_Objects() {}
145
147 : m_pProgramElf(other.m_pProgramElf ? new Elf(*other.m_pProgramElf) : nullptr),
148 m_ProgramStart(other.m_ProgramStart),
149 m_ProgramSize(other.m_ProgramSize),
150 m_ProgramBuffer(other.m_ProgramBuffer),
151 m_LoadedObjects(other.m_LoadedObjects),
152 m_Objects() {
153 // Tree iteration uses a tree-owned cursor. Walk our shallow node copy so
154 // copying a linker cannot disturb an active traversal of the source linker.
155 Tree<uintptr_t, SharedObject*> objects(other.m_Objects);
156 for (Tree<uintptr_t, SharedObject*>::Iterator it = objects.begin(); it != objects.end(); it++) {
157 uintptr_t key = it.key();
158 SharedObject* pSo = it.value();
159 m_Objects.insert(
160 key, new SharedObject(new Elf(*pSo->elf), pSo->file, pSo->buffer, pSo->address, pSo->size));
161 }
162}
163
164DynamicLinker::~DynamicLinker() {
165 // VirtualAddressSpace &va =
166 // Processor::information().getVirtualAddressSpace();
167
168 for (Tree<uintptr_t, SharedObject*>::Iterator it = m_Objects.begin(); it != m_Objects.end();
169 it++) {
170 SharedObject* pSo = it.value();
171 delete pSo->elf;
172 delete pSo;
173 }
174
175 delete m_pProgramElf;
176}
177
178bool DynamicLinker::loadProgram(File* pFile, bool bDryRun, bool bInterpreter,
179 String* sInterpreter) {
180 if (!pFile)
181 return false;
182
183 uintptr_t buffer = 0;
185 pFile, buffer, pFile->getSize(), MemoryMappedObject::Read);
186 if (!pMmFile) {
187 SYSCALL_ERROR(OutOfMemory);
188 return false;
189 }
190
191 String fileName;
192 pFile->getName(fileName);
193#if VERBOSE_KERNEL
194 NOTICE("DynamicLinker::loadProgram(" << fileName << ")");
195#endif
196
197 Elf* programElf = new Elf();
198 if (!programElf) {
200 SYSCALL_ERROR(OutOfMemory);
201 return false;
202 }
203
204 if (!bDryRun) {
205 delete m_pProgramElf;
206 m_pProgramElf = programElf;
207 if (!m_pProgramElf->create(reinterpret_cast<uint8_t*>(buffer), pFile->getSize())) {
208 ERROR("DynamicLinker: Main program ELF failed to create: `" << fileName << "' at " << buffer);
210
211 delete m_pProgramElf;
212 m_pProgramElf = 0;
213 return false;
214 }
215
217 if (!prepareNativeImageAllocation() ||
218 !m_pProgramElf->allocate(reinterpret_cast<uint8_t*>(buffer), pFile->getSize(),
219 m_ProgramStart, 0, false, &m_ProgramSize)) {
220 ERROR("DynamicLinker: Main program ELF failed to load: `" << fileName << "'");
222
223 delete m_pProgramElf;
224 m_pProgramElf = 0;
225 return false;
226 }
227
228 m_ProgramBuffer = buffer;
229 } else {
230 if (!programElf->createNeededOnly(reinterpret_cast<uint8_t*>(buffer), pFile->getSize())) {
231 ERROR("DynamicLinker: Main program ELF failed to create: `" << fileName << "' at " << buffer);
233
234 if (!bDryRun) {
235 delete m_pProgramElf;
236 m_pProgramElf = 0;
237 } else
238 delete programElf;
239 return false;
240 }
241 }
242
243 if (bInterpreter) {
244 if (!sInterpreter)
245 return false;
246 *sInterpreter = programElf->getInterpreter();
247 bool hasInterpreter = sInterpreter->length() > 0;
248 if (bDryRun) {
249 // Clean up the ELF
250 delete programElf;
251 m_pProgramElf = 0;
252
253 // Unmap this file - any future loadProgram will map it again.
255 }
256 return hasInterpreter;
257 }
258
259 List<char*>& dependencies = programElf->neededLibraries();
260
261 // Load all dependencies
262 for (List<char*>::Iterator it = dependencies.begin(); it != dependencies.end(); it++) {
263 // Extreme validation
264 if (!*it)
265 continue;
266 void* loadedObject = nullptr;
267 if (m_LoadedObjects.lookup(String(*it), loadedObject)) {
268 WARNING("Object `" << *it << "' has already been loaded");
269 continue;
270 }
271
272 String filename;
273 filename += "/usr/lib/";
274 filename += *it;
275 Directory::ChildLease dependencyLease;
276 File* pDependencyFile = VFS::instance().findRetained(filename, dependencyLease);
277 if (!pDependencyFile) {
278 ERROR("DynamicLinker: Dependency `" << filename << "' not found!");
279 if (!bDryRun) {
280 delete m_pProgramElf;
281 m_pProgramElf = 0;
282 } else
283 delete programElf;
284 return false;
285 }
286 while (pDependencyFile && pDependencyFile->isSymlink()) {
287 Directory::ChildLease targetLease;
288 pDependencyFile = Symlink::fromFile(pDependencyFile)->followLinkRetained(targetLease);
289 dependencyLease.swap(targetLease);
290 }
291 if (!pDependencyFile || !loadObject(pDependencyFile, bDryRun)) {
292 ERROR("DynamicLinker: Dependency `" << filename << "' failed to load!");
293 if (!bDryRun) {
294 delete m_pProgramElf;
295 m_pProgramElf = 0;
296 } else
297 delete programElf;
298 return false;
299 }
300
301 // Success! Add the filename of the library (NOT WITH LIBRARIES
302 // DIRECTORY) to the known loaded objects list.
303 if (!bDryRun)
304 m_LoadedObjects.insert(String(*it), reinterpret_cast<void*>(1));
305 }
306
307 if (!bDryRun)
308 initPlt(m_pProgramElf, 0);
309 else
310 delete programElf;
311
312 return true;
313}
314
315bool DynamicLinker::loadObject(File* pFile, bool bDryRun) {
316 uintptr_t buffer = 0;
317 size_t size;
318 uintptr_t loadBase = 0;
320 pFile, buffer, pFile->getSize(), MemoryMappedObject::Read);
321 if (!pMmFile) {
322 SYSCALL_ERROR(OutOfMemory);
323 return false;
324 }
325
326 Elf* pElf = new Elf();
327 if (!pElf) {
329 SYSCALL_ERROR(OutOfMemory);
330 return false;
331 }
332 SharedObject* pSo = 0;
333
334 String fileName;
335 pFile->getName(fileName);
336 NOTICE("DynamicLinker::loadObject(" << fileName << ")");
337
338 if (!bDryRun) {
339 if (!pElf->create(reinterpret_cast<uint8_t*>(buffer), pFile->getSize())) {
340 ERROR("DynamicLinker: ELF creation failed for file `" << pFile->getName() << "'");
341 delete pElf;
343 return false;
344 }
345
347 if (!prepareNativeImageAllocation() ||
348 !pElf->allocate(reinterpret_cast<uint8_t*>(buffer), pFile->getSize(), loadBase,
349 m_pProgramElf->getSymbolTable(), false, &size)) {
350 ERROR("DynamicLinker: ELF allocate failed for file `" << pFile->getName() << "'");
351 delete pElf;
353 return false;
354 }
355
356 pSo = new SharedObject(pElf, pMmFile, buffer, loadBase, size);
357
358 m_Objects.insert(loadBase, pSo);
359 } else {
360 if (!pElf->createNeededOnly(reinterpret_cast<uint8_t*>(buffer), pFile->getSize())) {
361 ERROR("DynamicLinker: ELF creation failed for file `" << pFile->getName() << "'");
362 delete pElf;
363 return false;
364 }
365 }
366
367 List<char*>& dependencies = pElf->neededLibraries();
368
369 // Load all dependencies
370 for (List<char*>::Iterator it = dependencies.begin(); it != dependencies.end(); it++) {
371 // Extreme validation
372 if (!*it)
373 continue;
374 void* loadedObject = nullptr;
375 if (m_LoadedObjects.lookup(String(*it), loadedObject)) {
376 WARNING("Object `" << *it << "' has already been loaded");
377 continue;
378 }
379
380 String filename;
381 filename += "/usr/lib/";
382 filename += *it;
383 Directory::ChildLease dependencyLease;
384 File* _pFile = VFS::instance().findRetained(filename, dependencyLease);
385 if (!_pFile) {
386 ERROR("DynamicLinker: Dependency `" << filename << "' not found!");
387 if (!bDryRun) {
388 if (loadBase) {
389 m_Objects.remove(loadBase);
390 }
391 delete pSo;
392 }
393 delete pElf;
394 return false;
395 }
396 while (_pFile && _pFile->isSymlink()) {
397 Directory::ChildLease targetLease;
398 _pFile = Symlink::fromFile(_pFile)->followLinkRetained(targetLease);
399 dependencyLease.swap(targetLease);
400 }
401 if (!_pFile || !loadObject(_pFile, bDryRun)) {
402 ERROR("DynamicLinker: Dependency `" << filename << "' failed to load!");
403 if (!bDryRun) {
404 if (loadBase) {
405 m_Objects.remove(loadBase);
406 }
407 delete pSo;
408 }
409 delete pElf;
410 return false;
411 }
412
413 // Success! Add the filename of the library (NOT WITH LIBRARIES
414 // DIRECTORY) to the known loaded objects list.
415 if (!bDryRun)
416 m_LoadedObjects.insert(String(*it), reinterpret_cast<void*>(1));
417 }
418
419 if (!bDryRun)
420 initPlt(pElf, loadBase);
421 else
422 delete pElf;
423
424 return true;
425}
426
427#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS)
428void DynamicLinker::setDemandPageAllocationHookForTest(physical_uintptr_t (*hook)()) {
429 g_DemandPageAllocationHook = hook;
430}
431
432void DynamicLinker::setDemandPageReadyHookForTest(void (*hook)(uintptr_t)) {
433 g_DemandPageReadyHook = hook;
434}
435
436void DynamicLinker::setDemandPageFreeHookForTest(void (*hook)(physical_uintptr_t)) {
437 g_DemandPageFreeHook = hook;
438}
439#endif
440
441bool DynamicLinker::loadDemandPage(Elf* pElf, uintptr_t buffer, size_t size, uintptr_t offset,
442 SymbolTable* pSymbols, uintptr_t address) {
443 VirtualAddressSpace& va = Processor::information().getVirtualAddressSpace();
444 const size_t pageSize = PhysicalMemoryManager::getPageSize();
445 const uintptr_t v = address & ~(pageSize - 1);
446
447 // Grab a physical page.
448 const physical_uintptr_t p =
449#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS)
450 g_DemandPageAllocationHook ? g_DemandPageAllocationHook() :
451#endif
452 PhysicalMemoryManager::instance().allocatePage();
453 if (!p) {
454 WARNING("IMAGE: allocatePage() failed in ElfImage::trap()");
455 return false;
456 }
457
458 bool loaded = false;
459 {
460 DemandPageStagingMapping staging(p);
461 if (!staging.valid()) {
462 WARNING("IMAGE: could not create a kernel staging mapping for vaddr: " << v);
463 releaseDemandPage(p);
464 return false;
465 }
466
467 ByteSet(reinterpret_cast<void*>(staging.address()), 0, pageSize);
468
469 // Keep all logical relocation addresses in the process address space, but
470 // direct writes to the private staging alias until the page is complete.
471 loaded = pElf->load(reinterpret_cast<uint8_t*>(buffer), size, offset, pSymbols, v, v + pageSize,
472 true, staging.address());
473 if (loaded) {
474 // Relocations can modify executable bytes after segment population, so
475 // publish only after cache maintenance covers the completed page.
476 Processor::flushDCacheAndInvalidateICache(staging.address(), staging.address() + pageSize);
477 }
478 }
479
480 if (!loaded) {
481 WARNING("LINKER: load() failed in DynamicLinker::trap()");
482 releaseDemandPage(p);
483 return false;
484 }
485
486#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS)
487 if (g_DemandPageReadyHook) {
488 g_DemandPageReadyHook(v);
489 }
490#endif
491
492 // Hosted map() uses MAP_FIXED and therefore cannot itself arbitrate two
493 // publishers. Keep the recheck and map in one short cross-host critical
494 // section so a completed page has exactly one winner.
495 LockGuard<Mutex> publishGuard(g_DemandPagePublishLock);
496 if (va.isMapped(reinterpret_cast<void*>(v))) {
497 releaseDemandPage(p);
498 return true;
499 }
500
501 if (!va.map(p, reinterpret_cast<void*>(v),
503 releaseDemandPage(p);
504 WARNING("IMAGE: map() failed in ElfImage::trap(): vaddr: " << v);
505 return false;
506 }
507
508 return true;
509}
510
511bool DynamicLinker::trap(uintptr_t address) {
512 Elf* pElf = 0;
513 uintptr_t offset = 0;
514 uintptr_t buffer = 0;
515 size_t size = 0;
516
517 if (address >= m_ProgramStart && address < m_ProgramStart + m_ProgramSize) {
518 pElf = m_pProgramElf;
519 offset = 0;
520 buffer = m_ProgramBuffer;
521 size = m_ProgramSize;
522 } else {
523 for (Tree<uintptr_t, SharedObject*>::Iterator it = m_Objects.begin(); it != m_Objects.end();
524 it++) {
525 SharedObject* pSo = it.value();
526
527 // Totally pedantic
528 EMIT_IF(ADDITIONAL_CHECKS) {
529 if (!pSo) {
530 ERROR("A null shared object was in the object list.");
531 continue;
532 }
533 }
534
535 if (address >= pSo->address && address < pSo->address + pSo->size) {
536 pElf = pSo->elf;
537 offset = pSo->address;
538 buffer = pSo->buffer;
539 size = pSo->size;
540 break;
541 }
542 }
543 }
544
545 if (!pElf)
546 return false;
547
548 return loadDemandPage(pElf, buffer, size, offset, m_pProgramElf->getSymbolTable(), address);
549}
550
552 return m_pProgramElf->getSymbolTable()->lookup(name, m_pProgramElf);
553}
554
556 const bool registered = PageFaultHandler::instance().registerHandler(this);
557 assert(registered);
558}
559
561 const bool unregistered = PageFaultHandler::instance().unregisterHandler(this);
562 assert(unregistered);
563}
564
565bool DLTrapHandler::trap(InterruptState& state, uintptr_t address, bool bIsWrite,
566 bool bWasPresent) {
567 if (bWasPresent) {
568 return false;
569 }
570
571 DynamicLinker* pL = Processor::information().getCurrentThread()->getParent()->getLinker();
572 if (!pL)
573 return false;
574 return pL->trap(address);
575}
576
577static bool init() {
578#if defined(PEDIGREE_HOSTED_PAGE_CONTENT_REGRESSIONS) && \
579 (!defined(PEDIGREE_HOSTED_DARWIN) || !PEDIGREE_HOSTED_DARWIN)
580 if (!runHostedPageContentRegressions()) {
581 return false;
582 }
583#endif
586 return true;
587}
588
589static void destroy() {}
590
591MODULE_INFO_NON_UNLOADABLE("linker", &init, &destroy, "vfs");
Memory-mapped file interface.
virtual bool trap(InterruptState &state, uintptr_t address, bool bIsWrite, bool bWasPresent)
void initPlt(Elf *pElf, uintptr_t value)
uintptr_t resolve(String name)
static uintptr_t resolvePlt(SyscallState &state)
bool trap(uintptr_t address)
bool loadObject(File *pFile, bool bDryRun=false)
bool loadProgram(File *pFile, bool bDryRun=false, bool bInterpreter=false, String *sInterpreter=0)
Definition Elf.h:201
String & getInterpreter()
bool createNeededOnly(uint8_t *pBuffer, size_t length)
bool create(uint8_t *pBuffer, size_t length)
List< char * > & neededLibraries()
bool load(uint8_t *pBuffer, size_t length, uintptr_t loadBase, SymbolTable *pSymtab=0, uintptr_t nStart=0, uintptr_t nEnd=~0, bool relocate=true, uintptr_t destinationBase=0)
bool allocate(uint8_t *pBuffer, size_t length, uintptr_t &loadBase, SymbolTable *pSymtab=0, bool bAllocate=true, size_t *pSize=0)
Definition File.h:75
String getName() const
Definition File.cc:782
virtual bool isSymlink()
Definition File.cc:800
static KernelCoreSyscallManager & instance()
uintptr_t registerSyscall(Function_t function, SyscallCallback func)
Definition List.h:61
Iterator begin()
Definition List.h:122
::Iterator< T, node_t > Iterator
Definition List.h:67
Iterator end()
Definition List.h:132
void unmap(MemoryMappedObject *pObj)
static MemoryMapManager & instance()
MemoryMappedObject * mapFile(File *pFile, uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms, size_t offset=0, bool bCopyOnWrite=true)
Special memory entity in the kernel's virtual address space.
Definition Mutex.h:56
EXPORTED_PUBLIC bool unregisterHandler(MemoryTrapHandler *pHandler)
EXPORTED_PUBLIC bool registerHandler(MemoryTrapHandler *pHandler)
static PageFaultHandler & instance()
static PhysicalMemoryManager & instance()
virtual void freePage(physical_uintptr_t page)=0
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
Process * getParent()
Definition Process.h:620
static ProcessorInformation & information()
static void flushDCacheAndInvalidateICache(uintptr_t startAddr, uintptr_t endAddr)
uintptr_t EXPORTED_PUBLIC lookup(const HashedStringView &name, Elf *pElf, Policy policy=LocalFirst, Binding *pBinding=0)
An iterator applicable for many data structures.
Definition Iterator.h:147
A key/value dictionary.
Definition Tree.h:33
Iterator begin()
Definition Tree.h:402
Iterator end()
Definition Tree.h:427
File * findRetained(const String &path, Directory::ChildLease &result, File *pStartNode=nullptr)
Definition VFS.cc:1042
static VFS & instance()
Definition VFS.cc:311
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual bool isMapped(void *virtualAddress)=0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual void unmap(void *virtualAddress)=0
MUST_USE_RESULT bool lookup(const String &key, T &value) const
Definition RadixTree.h:454
void insert(const String &key, const T &value)
Definition RadixTree.h:353