1 /* vi: set sw=4 ts=4: */
3 * A small little ldd implementation for uClibc
5 * Copyright (C) 2001 by Lineo, inc.
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
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.
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.
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
39 #include <sys/types.h>
47 struct library *lib_list = NULL;
51 Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
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) {
63 Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
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) {
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)
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) {
84 return (void *)dynp->d_un.d_val;
86 return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr );
92 int check_elf_header(Elf32_Ehdr const *const ehdr)
94 if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||
95 ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
96 ehdr->e_ident[EI_VERSION] != EV_CURRENT)
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)
108 struct stat filestat;
110 /* We need a writable copy of this string */
111 path = strdup(path_list);
113 fprintf(stderr, "Out of memory!\n");
117 /* Replace colons with zeros in path_parsed and count them */
118 for(i=strlen(path); i > 0; i--) {
126 for (i = 0; i < count; i++) {
128 strcat(result, path_n);
130 strcat(result, name);
131 if (stat (result, &filestat) == 0 && filestat.st_mode & S_IRUSR) {
135 path_n += (strlen(path_n) + 1);
141 void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_suid, struct library *lib)
145 struct stat filestat;
149 lib->path = "not found";
151 /* If this is a fully resolved name, our job is easy */
152 if (stat (lib->name, &filestat) == 0) {
153 lib->path = lib->name;
157 /* We need some elbow room here. Make some room...*/
160 fprintf(stderr, "Out of memory!\n");
164 /* This function must match the behavior of _dl_load_shared_library
165 * in readelflib1.c or things won't work out as expected... */
167 /* The ABI specifies that RPATH is searched first, so do that now. */
168 path = (char *)elf_find_dynamic(DT_RPATH, dynamic, ehdr, 0);
170 search_for_named_library(lib->name, buf, path);
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 */
185 path = getenv("LD_LIBRARY_PATH");
187 search_for_named_library(lib->name, buf, path);
196 /* FIXME -- add code to check the Cache here */
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:"
205 search_for_named_library(lib->name, buf, path);
213 static int add_library(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid, const char *s)
215 struct library *cur, *prev, *newlib=lib_list;
217 if (!s || !strlen(s))
220 for (cur = lib_list; cur; cur=cur->next) {
221 if(strcmp(cur->name, s)==0) {
222 /* Lib is already in the list */
227 /* Ok, this lib needs to be added to the list */
228 newlib = malloc(sizeof(struct library));
231 newlib->name = malloc(strlen(s));
232 strcpy(newlib->name, s);
233 newlib->resolved = 0;
236 /* Now try and locate where this library might be living... */
237 locate_library_file(ehdr, dynamic, strtab, is_setuid, newlib);
239 //printf("adding '%s' to '%s'\n", newlib->name, newlib->path);
243 for (cur = prev = lib_list; cur->next; prev=cur, cur=cur->next); /* nothing */
251 static void find_needed_libraries(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
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);
262 static void find_elf_interpreter(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *strtab, int is_setuid)
265 phdr = elf_find_phdr_type(PT_INTERP, ehdr);
267 add_library(ehdr, dynamic, strtab, is_setuid, (char*)ehdr + phdr->p_offset);
271 /* map the .so, and locate interesting pieces */
272 int find_dependancies(char* filename)
278 Elf32_Ehdr *ehdr = NULL;
279 Elf32_Shdr *dynsec = NULL;
280 Elf32_Dyn *dynamic = NULL;
284 fprintf(stderr, "No filename specified.\n");
287 if (!(thefile = fopen(filename, "r"))) {
291 if (fstat(fileno(thefile), &statbuf) < 0) {
296 if (statbuf.st_size < sizeof(Elf32_Ehdr))
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);
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);
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);
314 if (ehdr->e_type == ET_EXEC) {
315 if (statbuf.st_mode & S_ISUID)
317 if ((statbuf.st_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
321 fprintf(stderr, "%s: is setuid\n", filename);
324 dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
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);
330 find_elf_interpreter(ehdr, dynamic, dynstr, is_suid);
337 int main( int argc, char** argv)
340 char *filename = argv[1];
345 fprintf(stderr, "No filename specified.\n");
349 find_dependancies(filename);
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) {
357 //printf("checking sub-depends for '%s\n", cur->path);
358 find_dependancies(cur->path);
366 for (cur = lib_list; cur; cur=cur->next) {
367 printf("\t%s => %s\n", cur->name, cur->path);