1
/* vi: set sw=4 ts=4: */
3
* A small little ldd implementation for uClibc
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>
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
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.
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.
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
39
#include <sys/types.h>
51
struct library *lib_list = NULL;
52
char not_found[] = "not found";
56
Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
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) {
68
Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
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) {
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)
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) {
89
return (void *)dynp->d_un.d_val;
91
return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr );
97
int check_elf_header(Elf32_Ehdr const *const ehdr)
99
if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||
100
ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
101
ehdr->e_ident[EI_VERSION] != EV_CURRENT)
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)
114
struct stat filestat;
116
/* We need a writable copy of this string */
117
path = strdup(path_list);
119
fprintf(stderr, "Out of memory!\n");
122
/* Eliminate all double //s */
124
while((path_n=strstr(path_n, "//"))) {
126
memmove(path_n, path_n+1, i-1);
129
/* Replace colons with zeros in path_list and count them */
130
for(i=strlen(path); i > 0; i--) {
138
for (i = 0; i < count; i++) {
140
strcat(result, path_n);
142
strcat(result, name);
143
if (stat (result, &filestat) == 0 && filestat.st_mode & S_IRUSR) {
147
path_n += (strlen(path_n) + 1);
153
void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_suid, struct library *lib)
157
struct stat filestat;
159
/* If this is a fully resolved name, our job is easy */
160
if (stat (lib->name, &filestat) == 0) {
161
lib->path = lib->name;
165
/* We need some elbow room here. Make some room...*/
168
fprintf(stderr, "Out of memory!\n");
172
/* This function must match the behavior of _dl_load_shared_library
173
* in readelflib1.c or things won't work out as expected... */
175
/* The ABI specifies that RPATH is searched first, so do that now. */
176
path = (char *)elf_find_dynamic(DT_RPATH, dynamic, ehdr, 0);
178
search_for_named_library(lib->name, buf, path);
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 */
191
path = getenv("LD_LIBRARY_PATH");
193
search_for_named_library(lib->name, buf, path);
201
/* FIXME -- add code to check the Cache here */
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:"
212
search_for_named_library(lib->name, buf, path);
217
lib->path = not_found;
221
static int add_library(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid, char *s)
223
char *tmp, *tmp1, *tmp2;
224
struct library *cur, *newlib=lib_list;
226
if (!s || !strlen(s))
229
/* We add libc.so.0 elsewhere */
230
if (strcmp(s, UCLIBC_LDSO)==0)
240
for (cur = lib_list; cur; cur=cur->next) {
241
/* Check if this library is already in the list */
242
tmp1 = tmp2 = cur->name;
248
if(strcmp(tmp2, s)==0) {
249
//printf("find_elf_interpreter is skipping '%s' (already in list)\n", cur->name);
254
/* Ok, this lib needs to be added to the list */
255
newlib = malloc(sizeof(struct library));
258
newlib->name = malloc(strlen(s)+1);
259
strcpy(newlib->name, s);
260
newlib->resolved = 0;
264
/* Now try and locate where this library might be living... */
265
locate_library_file(ehdr, dynamic, strtab, is_setuid, newlib);
267
//printf("add_library is adding '%s' to '%s'\n", newlib->name, newlib->path);
271
for (cur = lib_list; cur->next; cur=cur->next); /* nothing */
278
static void find_needed_libraries(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
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);
289
static void find_elf_interpreter(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
291
static int been_there_done_that=0;
294
if (been_there_done_that==1)
296
been_there_done_that=1;
297
phdr = elf_find_phdr_type(PT_INTERP, ehdr);
299
struct library *cur, *newlib=NULL;
300
char *s = (char*)ehdr + phdr->p_offset;
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);
320
newlib = malloc(sizeof(struct library));
323
newlib->name = malloc(strlen(s)+1);
324
strcpy(newlib->name, s);
325
newlib->path = newlib->name;
326
newlib->resolved = 1;
329
//printf("find_elf_interpreter is adding '%s' to '%s'\n", newlib->name, newlib->path);
333
for (cur = lib_list; cur->next; cur=cur->next); /* nothing */
339
/* map the .so, and locate interesting pieces */
340
int find_dependancies(char* filename)
346
Elf32_Ehdr *ehdr = NULL;
347
Elf32_Shdr *dynsec = NULL;
348
Elf32_Dyn *dynamic = NULL;
350
if (filename == not_found)
354
fprintf(stderr, "No filename specified.\n");
357
if (!(thefile = fopen(filename, "r"))) {
361
if (fstat(fileno(thefile), &statbuf) < 0) {
366
if (statbuf.st_size < sizeof(Elf32_Ehdr))
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);
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);
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);
384
if (ehdr->e_type == ET_EXEC) {
385
if (statbuf.st_mode & S_ISUID)
387
if ((statbuf.st_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
391
fprintf(stderr, "%s: is setuid\n", filename);
394
dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
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);
400
find_elf_interpreter(ehdr, dynamic, dynstr, is_suid);
407
int main( int argc, char** argv)
410
char *filename = argv[1];
415
fprintf(stderr, "No filename specified.\n");
419
find_dependancies(filename);
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) {
427
//printf("checking sub-depends for '%s\n", cur->path);
428
find_dependancies(cur->path);
437
for (cur = lib_list; cur; cur=cur->next) {
439
printf("\t%s => %s\n", cur->name, cur->path);
442
printf("\tnot a dynamic executable\n");