xref: /haiku/src/system/libroot/posix/dlfcn.c (revision 893988af824e65e49e55f517b157db8386e8002b)
1 /*
2  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2002, Manuel J. Petit. All rights reserved.
7  * Distributed under the terms of the NewOS License.
8  */
9 
10 
11 #include <libroot_private.h>
12 
13 #include <dlfcn.h>
14 #include <string.h>
15 
16 #include <runtime_loader.h>
17 #include <user_runtime.h>
18 
19 
20 static status_t sStatus;
21 	// Note, this is not thread-safe
22 
23 
24 void *
25 dlopen(char const *name, int mode)
26 {
27 	void* handle;
28 	image_id imageID = __gRuntimeLoader->load_library(name, mode, &handle);
29 
30 	sStatus = imageID >= 0 ? B_OK : imageID;
31 
32 	return imageID >= 0 ? handle : NULL;
33 }
34 
35 
36 void *
37 dlsym(void *handle, char const *name)
38 {
39 	void* location;
40 	status_t status;
41 	void* caller = NULL;
42 
43 	if (handle == RTLD_NEXT)
44 		caller = __arch_get_caller();
45 
46 	status = __gRuntimeLoader->get_library_symbol(handle, caller, name,
47 		&location);
48 	sStatus = status;
49 
50 	if (status < B_OK)
51 		return NULL;
52 
53 	return location;
54 }
55 
56 
57 int
58 dlclose(void *handle)
59 {
60 	return sStatus = __gRuntimeLoader->unload_library(handle);
61 }
62 
63 
64 char *
65 dlerror(void)
66 {
67 	if (sStatus < B_OK)
68 		return strerror(sStatus);
69 
70 	return NULL;
71 }
72 
73 
74 int
75 dladdr(void *addr, Dl_info *info)
76 {
77 // TODO: This can be implemented more efficiently in the runtime loader.
78 // get_library_symbol() already has the code doing that.
79 	char curSymName[NAME_MAX];
80 	static char symName[NAME_MAX];
81 	static char imageName[MAXPATHLEN];
82 	void *symLocation;
83 	int32 cookie;
84 	int32 symType, symNameLength;
85 	uint32 symIndex;
86 	image_info imageInfo;
87 
88 	if (info == NULL)
89 		return 0;
90 
91 	imageName[0] = '\0';
92 	symName[0] = '\0';
93 	info->dli_fname = imageName;
94 	info->dli_saddr = NULL;
95 	info->dli_sname = symName;
96 
97 	cookie = 0;
98 	while (get_next_image_info(0, &cookie, &imageInfo) == B_OK) {
99 		// check if the image holds the symbol
100 		if ((addr_t)addr >= (addr_t)imageInfo.text
101 			&& (addr_t)addr < (addr_t)imageInfo.text + imageInfo.text_size)  {
102 			strlcpy(imageName, imageInfo.name, MAXPATHLEN);
103 			info->dli_fbase = imageInfo.text;
104 			symIndex = 0;
105 			symNameLength = NAME_MAX;
106 
107 			while (get_nth_image_symbol(imageInfo.id, symIndex, curSymName,
108 					&symNameLength, &symType, &symLocation) == B_OK) {
109 				// check if symbol is the nearest until now
110 				if (symType == B_SYMBOL_TYPE_TEXT
111 					&& symLocation <= addr
112 					&& symLocation >= info->dli_saddr) {
113 					strlcpy(symName, curSymName, NAME_MAX);
114 					info->dli_saddr = symLocation;
115 
116 					// stop here if exact match
117 					if (info->dli_saddr == addr)
118 						return 1;
119 				}
120 				symIndex++;
121 				symNameLength = NAME_MAX;
122 			}
123 			break;
124 		}
125 	}
126 
127 	if (info->dli_saddr != NULL)
128 		return 1;
129 
130 	return 0;
131 }
132 
133 
134 // __libc_dl*** wrappers
135 // We use a mixed glibc / bsd libc, and glibc wants these
136 void *__libc_dlopen(const char *name);
137 void *__libc_dlsym(void *handle, const char *name);
138 void __libc_dlclose(void *handle);
139 
140 void *
141 __libc_dlopen(const char *name)
142 {
143 	return dlopen(name, 0);
144 }
145 
146 
147 void *
148 __libc_dlsym(void *handle, const char *name)
149 {
150 	return dlsym(handle, name);
151 }
152 
153 
154 void
155 __libc_dlclose(void *handle)
156 {
157 	dlclose(handle);
158 }
159