1//------------------------------------------------------------------------------
2//	Copyright (c) 2003, Ingo Weinhold
3//
4//	Permission is hereby granted, free of charge, to any person obtaining a
5//	copy of this software and associated documentation files (the "Software"),
6//	to deal in the Software without restriction, including without limitation
7//	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8//	and/or sell copies of the Software, and to permit persons to whom the
9//	Software is furnished to do so, subject to the following conditions:
10//
11//	The above copyright notice and this permission notice shall be included in
12//	all copies or substantial portions of the Software.
13//
14//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19//	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20//	DEALINGS IN THE SOFTWARE.
21//
22//	File Name:		ElfImage.cpp
23//	Author:			Ingo Weinhold (bonefish@users.sf.net)
24//	Description:	Implementation of ElfImage, a class encapsulating
25//					a loaded ELF image, providing support for accessing the
26//					image's symbols and their relocation entries.
27//------------------------------------------------------------------------------
28
29#include <new>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <List.h>
35
36#include <debug/debug_support.h>
37
38#include "ElfImage.h"
39
40
41static status_t
42get_static_image_symbol(image_id image, const char* name, int32 symbolType,
43	void** _address)
44{
45	// try standard lookup first
46	status_t error =  get_image_symbol(image, name, symbolType, _address);
47	if (error == B_OK)
48		return B_OK;
49
50	// get an image info
51	image_info imageInfo;
52	error = get_image_info(image, &imageInfo);
53	if (error != B_OK)
54		return error;
55
56	// get a symbol iterator
57	debug_symbol_iterator* iterator;
58	error = debug_create_file_symbol_iterator(imageInfo.name, &iterator);
59	if (error != B_OK)
60		return error;
61
62	// get the unrelocated image info
63	image_info unrelocatedImageInfo;
64	error = debug_get_symbol_iterator_image_info(iterator,
65		&unrelocatedImageInfo);
66	if (error != B_OK) {
67		debug_delete_symbol_iterator(iterator);
68		return error;
69	}
70
71	// iterate through the symbols
72	int32 nameLength = strlen(name);
73	while (true) {
74		char foundName[nameLength + 1];
75		int32 foundType;
76		void* foundAddress;
77		size_t foundSize;
78		if (debug_next_image_symbol(iterator, foundName, nameLength + 1,
79				&foundType, &foundAddress, &foundSize) != B_OK) {
80			debug_delete_symbol_iterator(iterator);
81			return B_ENTRY_NOT_FOUND;
82		}
83
84		if (strcmp(foundName, name) == 0
85			&& (symbolType == B_SYMBOL_TYPE_ANY || foundType == symbolType)) {
86			*_address = (void*)((addr_t)foundAddress + (addr_t)imageInfo.text
87				- (addr_t)unrelocatedImageInfo.text);
88			debug_delete_symbol_iterator(iterator);
89			return B_OK;
90		}
91	}
92}
93
94
95// ElfImage
96
97// constructor
98ElfImage::ElfImage()
99	: fImage(-1),
100	  fFile(),
101	  fTextAddress(NULL),
102	  fDataAddress(NULL),
103	  fGotAddress(NULL)
104{
105}
106
107// destructor
108ElfImage::~ElfImage()
109{
110	Unset();
111}
112
113// SetTo
114status_t
115ElfImage::SetTo(image_id image)
116{
117	Unset();
118	status_t error = _SetTo(image);
119	if (error)
120		Unset();
121	return error;
122}
123
124// Unset
125void
126ElfImage::Unset()
127{
128	fFile.Unset();
129	fImage = -1;
130	fTextAddress = NULL;
131	fDataAddress = NULL;
132	fGotAddress = NULL;
133}
134
135// Unload
136void
137ElfImage::Unload()
138{
139	fFile.Unload();
140}
141
142// FindSymbol
143status_t
144ElfImage::FindSymbol(const char* symbolName, void** address)
145{
146	return get_image_symbol(fImage, symbolName, B_SYMBOL_TYPE_ANY, address);
147}
148
149// GetSymbolRelocations
150status_t
151ElfImage::GetSymbolRelocations(const char* symbolName, BList* relocations)
152{
153	status_t error = B_OK;
154	ElfRelocation relocation;
155	for (ElfRelocationIterator it(&fFile); it.GetNext(&relocation); ) {
156		uint32 type = relocation.GetType();
157		// get the symbol
158		ElfSymbol symbol;
159		if ((type == R_GLOB_DAT || type == R_JUMP_SLOT)
160			&& relocation.GetSymbol(&symbol) == B_OK
161			&& symbol.GetName()) {
162			// only undefined symbols with global binding
163			if ((symbol.GetBinding() == STB_GLOBAL
164				 || symbol.GetBinding() == STB_WEAK)
165				&& (symbol.GetTargetSectionIndex() == SHN_UNDEF
166					|| symbol.GetTargetSectionIndex()
167					   >= (uint32)fFile.CountSections())
168				&& !strcmp(symbol.GetName(), symbolName)) {
169				// get the address of the GOT entry for the symbol
170				void** gotEntry
171					= (void**)(fTextAddress + relocation.GetOffset());
172				if (!relocations->AddItem(gotEntry)) {
173					error = B_NO_MEMORY;
174					break;
175				}
176			}
177		}
178	}
179	return error;
180}
181
182
183// _SetTo
184status_t
185ElfImage::_SetTo(image_id image)
186{
187	// get an image info
188	image_info imageInfo;
189	status_t error = get_image_info(image, &imageInfo);
190	if (error != B_OK)
191		return error;
192	fImage = imageInfo.id;
193	// get the address of global offset table
194	error = get_static_image_symbol(image, "_GLOBAL_OFFSET_TABLE_",
195		B_SYMBOL_TYPE_ANY, (void**)&fGotAddress);
196	if (error != B_OK)
197		return error;
198	fTextAddress = (uint8*)imageInfo.text;
199	fDataAddress = (uint8*)imageInfo.data;
200	// init the file
201	error = fFile.SetTo(imageInfo.name);
202	if (error != B_OK)
203		return error;
204	return B_OK;
205}
206
207