]> Git Repo - uclibc-ng.git/blob - ldso/util/ldd.c
search_for_named_library forgot to wipe the target string, so each time
[uclibc-ng.git] / ldso / util / ldd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * A small little ldd implementation for uClibc
4  *
5  * Copyright (C) 2001 by Lineo, inc.
6  * Written by Erik Andersen <[email protected]>, <[email protected]>
7  *
8  * Several functions in this file (specifically, elf_find_section_type(),
9  * elf_find_phdr_type(), and elf_find_dynamic(), were stolen from elflib.c from
10  * elfvector (http://www.BitWagon.com/elfvector.html) by John F. Reiser
11  * <[email protected]>, and which is copyright 2000 BitWagon Software LLC
12  * (GPL2).
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  * General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27  *
28  */
29
30
31 #include <elf.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40
41 struct library {
42         char *name;
43         int resolved;
44         char *path;
45         struct library *next;
46 };
47 struct library *lib_list = NULL;
48
49
50
51 Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
52 {
53         int j;
54         Elf32_Shdr *shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr);
55         for (j = ehdr->e_shnum; --j>=0; ++shdr) {
56                 if (shdr->sh_type == key) {
57                         return shdr;
58                 }
59         }
60         return NULL;
61 }
62
63 Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
64 {
65         int j;
66         Elf32_Phdr *phdr = (Elf32_Phdr *)(ehdr->e_phoff + (char *)ehdr);
67         for (j = ehdr->e_phnum; --j>=0; ++phdr) {
68                 if (type==phdr->p_type) {
69                         return phdr;
70                 }
71         }
72         return NULL;
73 }
74
75 /* Returns value if return_val==1, ptr otherwise */ 
76 void * elf_find_dynamic(int const key, Elf32_Dyn *dynp, 
77         Elf32_Ehdr *ehdr, int return_val)
78 {
79         Elf32_Phdr *pt_text = elf_find_phdr_type(PT_LOAD, ehdr);
80         unsigned tx_reloc = pt_text->p_vaddr - pt_text->p_offset;
81         for (; DT_NULL!=dynp->d_tag; ++dynp) {
82                 if (dynp->d_tag == key) {
83                         if (return_val == 1)
84                                 return (void *)dynp->d_un.d_val;
85                         else
86                                 return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr );
87                 }
88         }
89         return NULL;
90 }
91
92 int check_elf_header(Elf32_Ehdr const *const ehdr)
93 {
94         if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||  
95                         ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
96                         ehdr->e_ident[EI_VERSION] != EV_CURRENT) 
97         {
98                 return 1;
99         }
100         return 0;
101 }
102
103 /* This function must exactly match that in uClibc/ldso/util/ldd.c */
104 static void search_for_named_library(char *name, char *result, const char *path_list)
105 {
106         int i, count = 0;
107         char *path, *path_n;
108         struct stat filestat;
109
110         /* We need a writable copy of this string */
111         path = strdup(path_list);
112         if (!path) {
113                 fprintf(stderr, "Out of memory!\n");
114                 exit(EXIT_FAILURE);
115         }
116
117         /* Replace colons with zeros in path_parsed and count them */
118         for(i=strlen(path); i > 0; i--) {
119                 if (path[i]==':') {
120                         path[i]=0;
121                         count++;
122                 }
123         }
124
125         path_n = path;
126         for (i = 0; i < count; i++) {
127                 *result = '\0';
128                 strcat(result, path_n); 
129                 strcat(result, "/"); 
130                 strcat(result, name);
131                 if (stat (result, &filestat) == 0 && filestat.st_mode & S_IRUSR) {
132                         free(path);
133                         return;
134                 }
135                 path_n += (strlen(path_n) + 1);
136         }
137         free(path);
138         *result = '\0';
139 }
140
141 void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_suid, struct library *lib)
142 {
143         char *buf;
144         char *path;
145         struct stat filestat;
146         
147         
148
149         lib->path = "not found";
150
151         /* If this is a fully resolved name, our job is easy */
152         if (stat (lib->name, &filestat) == 0) {
153                 lib->path = lib->name;
154                 return;
155         }
156
157         /* We need some elbow room here.  Make some room...*/
158         buf = malloc(1024);
159         if (!buf) {
160                 fprintf(stderr, "Out of memory!\n");
161                 exit(EXIT_FAILURE);
162         }
163
164         /* This function must match the behavior of _dl_load_shared_library
165          * in readelflib1.c or things won't work out as expected... */
166
167         /* The ABI specifies that RPATH is searched first, so do that now.  */
168         path = (char *)elf_find_dynamic(DT_RPATH, dynamic, ehdr, 0);
169         if (path) {
170                 search_for_named_library(lib->name, buf, path);
171                 if (*buf != '\0') {
172                         lib->path = buf;
173                         return;
174                 } else {
175                         free(buf);
176                 }
177         }
178
179         /* Next check LD_{ELF_}LIBRARY_PATH if specified and allowed.
180          * Since this app doesn't actually run an executable I will skip
181          * the suid check, and just use LD_{ELF_}LIBRARY_PATH if set */
182         if (is_suid==1)
183                 path = NULL;
184         else
185                 path = getenv("LD_LIBRARY_PATH");
186         if (path) {
187                 search_for_named_library(lib->name, buf, path);
188                 if (*buf != '\0') {
189                         lib->path = buf;
190                         return;
191                 } else {
192                         free(buf);
193                 }
194         }
195
196         /* FIXME -- add code to check the Cache here */ 
197
198         /* Lastly, search the standard list of paths for the library */
199         path =  UCLIBC_PREFIX "/usr/lib:"
200                         UCLIBC_PREFIX "/lib:"
201                         UCLIBC_DEVEL_PREFIX "/lib:"
202                         UCLIBC_BUILD_DIR "/lib:"
203                         "/usr/lib:"
204                         "/lib";
205         search_for_named_library(lib->name, buf, path);
206         if (*buf != '\0') {
207                 lib->path = buf;
208         } else { 
209                 free(buf);
210         }
211 }
212
213 static int add_library(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid, const char *s)
214 {
215         struct library *cur, *prev, *newlib=lib_list;
216
217         if (!s || !strlen(s))
218                 return 1;
219
220         for (cur = lib_list; cur; cur=cur->next) {
221                 if(strcmp(cur->name, s)==0) {
222                         /* Lib is already in the list */
223                         return 0;
224                 }
225         }
226
227         /* Ok, this lib needs to be added to the list */
228         newlib = malloc(sizeof(struct library));
229         if (!newlib)
230                 return 1;
231         newlib->name = malloc(strlen(s));
232         strcpy(newlib->name, s);
233         newlib->resolved = 0;
234         newlib->next = NULL;
235
236         /* Now try and locate where this library might be living... */
237         locate_library_file(ehdr, dynamic, strtab, is_setuid, newlib);
238
239         //printf("adding '%s' to '%s'\n", newlib->name, newlib->path);
240         if (!lib_list) {
241                 lib_list = newlib;
242         } else {
243                 for (cur = prev = lib_list;  cur->next; prev=cur, cur=cur->next); /* nothing */
244                 cur = newlib;
245                 prev->next = cur;
246         }
247         return 0;
248 }
249
250
251 static void find_needed_libraries(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
252 {
253         Elf32_Dyn  *dyns;
254
255         for (dyns=dynamic; dyns->d_tag!=DT_NULL; ++dyns) {
256                 if (dyns->d_tag == DT_NEEDED) {
257                         add_library(ehdr, dynamic, strtab, is_setuid, (char*)strtab + dyns->d_un.d_val);
258                 }
259         }
260 }
261     
262 static void find_elf_interpreter(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
263 {
264         Elf32_Phdr *phdr;
265         phdr = elf_find_phdr_type(PT_INTERP, ehdr);
266         if (phdr) {
267                 add_library(ehdr, dynamic, strtab, is_setuid, (char*)ehdr + phdr->p_offset);
268         }
269 }
270
271 /* map the .so, and locate interesting pieces */
272 int find_dependancies(char* filename)
273 {
274         int is_suid = 0;
275         FILE *thefile;
276         struct stat statbuf;
277         char *dynstr=NULL;
278         Elf32_Ehdr *ehdr = NULL;
279         Elf32_Shdr *dynsec = NULL;
280         Elf32_Dyn *dynamic = NULL;
281
282
283         if (!filename) {
284                 fprintf(stderr, "No filename specified.\n");
285                 exit(EXIT_FAILURE);
286         }
287         if (!(thefile = fopen(filename, "r"))) {
288                 perror(filename);
289                 exit(EXIT_FAILURE);
290         }
291         if (fstat(fileno(thefile), &statbuf) < 0) {
292                 perror(filename);
293                 exit(EXIT_FAILURE);
294         }
295
296         if (statbuf.st_size < sizeof(Elf32_Ehdr))
297                 goto foo;
298
299         /* mmap the file to make reading stuff from it effortless */
300         ehdr = (Elf32_Ehdr *)mmap(0, statbuf.st_size, 
301                         PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0);
302
303 foo:
304         /* Check if this looks like a legit ELF file */
305         if (check_elf_header(ehdr)) {
306                 fprintf(stderr, "%s: not an ELF file.\n", filename);
307                 exit(EXIT_FAILURE);
308         }
309         /* Check if this is the right kind of ELF file */
310         if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
311                 fprintf(stderr, "%s: not a dynamic executable\n", filename);
312                 exit(EXIT_FAILURE);
313         }
314         if (ehdr->e_type == ET_EXEC) {
315                 if (statbuf.st_mode & S_ISUID)
316                         is_suid = 1;
317                 if ((statbuf.st_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
318                         is_suid = 1;
319                 /* FIXME */
320                 if (is_suid)
321                         fprintf(stderr, "%s: is setuid\n", filename);
322         }
323
324         dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
325         if (dynsec) {
326                 dynamic = (Elf32_Dyn*)(dynsec->sh_offset + (int)ehdr);
327                 dynstr = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0);
328                 find_needed_libraries(ehdr, dynamic, dynstr, is_suid);
329         }
330         find_elf_interpreter(ehdr, dynamic, dynstr, is_suid);
331         
332         return 0;
333 }
334
335
336
337 int main( int argc, char** argv)
338 {
339         int got_em_all=1;
340         char *filename = argv[1];
341         struct library *cur;
342
343
344         if (!filename) {
345                 fprintf(stderr, "No filename specified.\n");
346                 exit(EXIT_FAILURE);
347         }
348
349         find_dependancies(filename);
350         
351         while(got_em_all) {
352                 got_em_all=0;
353                 /* Keep walking the list till everybody is resolved */
354                 for (cur = lib_list; cur; cur=cur->next) {
355                         if (cur->resolved == 0 && cur->path) {
356                                 got_em_all=1;
357                                 //printf("checking sub-depends for '%s\n", cur->path);
358                                 find_dependancies(cur->path);
359                                 cur->resolved = 1;
360                         }
361                 }
362         }
363
364         
365         /* Print the list */
366         for (cur = lib_list; cur; cur=cur->next) {
367                 printf("\t%s => %s\n", cur->name, cur->path);
368         }
369
370         return 0;
371 }
372
This page took 0.048133 seconds and 4 git commands to generate.