~ubuntu-branches/ubuntu/breezy/uclibc/breezy

« back to all changes in this revision

Viewing changes to ldso/util/ldd.c

  • Committer: Bazaar Package Importer
  • Author(s): David Schleef
  • Date: 2005-04-18 13:29:53 UTC
  • mfrom: (1.1.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050418132953-hzuzafmpkxuj0gvj
Tags: 0.9.27-1
* New upstream release.
* Acknowledge NMU (Closes: #268989) and fix the bug it caused
  (Closes: #284326)
* Add gross versioned dependency for gcc-3.3, and make sure we use
  gcc-3.3 in the gcc wrapper. (Closes: #304806)

Show diffs side-by-side

added added

removed removed

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