xref: /netbsd-src/usr.bin/ldd/ldd.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: ldd.c,v 1.1 1996/12/16 19:59:56 cgd Exp $	*/
2 
3 /*
4  * Copyright 1996 John D. Polstra.
5  * Copyright 1996 Matt Thomas <matt@3am-software.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by John Polstra.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/mman.h>
44 #include <dirent.h>
45 
46 #include "debug.h"
47 #include "rtld.h"
48 
49 /*
50  * Data declarations.
51  */
52 const char *_rtld_error_message;	/* Message for dlopen(), or NULL */
53 bool _rtld_trust;		/* False for setuid and setgid programs */
54 Obj_Entry *_rtld_objlist;	/* Head of linked list of shared objects */
55 Obj_Entry **_rtld_objtail = &_rtld_objlist;
56 				/* Link field of last object in list */
57 Obj_Entry *_rtld_objmain;	/* The main program shared object */
58 
59 Search_Path *_rtld_paths;
60 
61 static void print_needed(Obj_Entry *);
62 
63 
64 /*
65  * Main entry point for dynamic linking.  The argument is the stack
66  * pointer.  The stack is expected to be laid out as described in the
67  * SVR4 ABI specification, Intel 386 Processor Supplement.  Specifically,
68  * the stack pointer points to a word containing ARGC.  Following that
69  * in the stack is a null-terminated sequence of pointers to argument
70  * strings.  Then comes a null-terminated sequence of pointers to
71  * environment strings.  Finally, there is a sequence of "auxiliary
72  * vector" entries.
73  *
74  * This function returns the entry point for the main program in %eax,
75  * and the dynamic linker's exit procedure in %edx.  We accomplish this
76  * by declaring the return value to have the 64-bit type "long long".
77  * Such values are returned with their most-significant 32 bits in %edx,
78  * and their least-significant 32 bits in %eax.
79  */
80 int
81 main(
82     int argc,
83     char **argv)
84 {
85 #ifdef DEBUG
86     debug = 1;
87 #endif
88     _rtld_add_paths(&_rtld_paths, RTLD_DEFAULT_LIBRARY_PATH);
89 
90 
91     _rtld_trust = geteuid() == getuid() && getegid() == getgid();
92 
93     if (_rtld_trust) {
94 	_rtld_add_paths(&_rtld_paths, getenv("LD_LIBRARY_PATH"));
95     }
96 
97     for (argc--, argv++; argc != 0; argc--, argv++) {
98 	int fd = open(*argv, O_RDONLY);
99 	if (fd == -1) {
100 	    warn("%s", *argv);
101 	    continue;
102 	}
103 	_rtld_objmain = _rtld_map_object(*argv, fd);
104 	close(fd);
105 	if (_rtld_objmain == NULL) {
106 	    warnx("%s", _rtld_error_message);
107 	    continue;
108 	}
109 
110 	_rtld_objmain->path = *argv;
111 	_rtld_objmain->mainprog = true;
112 	_rtld_digest_dynamic(_rtld_objmain);
113 
114 	/* Link the main program into the list of objects. */
115 	*_rtld_objtail = _rtld_objmain;
116 	_rtld_objtail = &_rtld_objmain->next;
117 	++_rtld_objmain->refcount;
118 
119 	(void) _rtld_load_needed_objects(_rtld_objmain);
120 
121 	printf("%s:\n", _rtld_objmain->path);
122 	print_needed(_rtld_objmain);
123 
124 	while (_rtld_objlist != NULL) {
125 	    Obj_Entry *obj = _rtld_objlist;
126 	    _rtld_objlist = obj->next;
127 	    while (obj->rpaths != NULL) {
128 		const Search_Path *rpath = obj->rpaths;
129 		obj->rpaths = rpath->sp_next;
130 		free((void *) rpath->sp_path);
131 		free((void *) rpath);
132 	    }
133 	    while (obj->needed != NULL) {
134 		const Needed_Entry *needed = obj->needed;
135 		obj->needed = needed->next;
136 		free((void *) needed);
137 	    }
138 	    (void) munmap(obj->relocbase, obj->mapsize);
139 	    free(obj->path);
140 	    free(obj);
141 	}
142 
143 	_rtld_objmain = NULL;
144 	_rtld_objtail = &_rtld_objlist;
145     }
146     return 0;
147 }
148 
149 /*
150  * Error reporting function.  Use it like printf.  If formats the message
151  * into a buffer, and sets things up so that the next call to dlerror()
152  * will return the message.
153  */
154 void
155 _rtld_error(
156     const char *fmt, ...)
157 {
158     static char buf[512];
159     va_list ap;
160     va_start(ap, fmt);
161     xvsnprintf(buf, sizeof buf, fmt, ap);
162     _rtld_error_message = buf;
163     va_end(ap);
164 }
165 
166 static void
167 print_needed(
168     Obj_Entry *obj)
169 {
170     const Needed_Entry *needed;
171 
172     for (needed = obj->needed; needed != NULL; needed = needed->next) {
173 	char libnamebuf[200];
174 	const char *libname = obj->strtab + needed->name, *cp;
175 	if (strncmp(libname, "lib", 3) == 0
176 		&& (cp = strstr(libname, ".so")) != NULL) {
177 	    strcpy(libnamebuf, "-l");
178 	    memcpy(&libnamebuf[2], libname + 3, cp - (libname + 3));
179 	    strcpy(&libnamebuf[cp - (libname + 3) + 2], cp + 3);
180 	    libname = libnamebuf;
181 	}
182 
183 	if (needed->obj != NULL) {
184 	    print_needed(needed->obj);
185 	    if (!needed->obj->printed) {
186 		printf("\t %s => %s\n", libname, needed->obj->path);
187 		needed->obj->printed = 1;
188 	    }
189 	} else {
190 	    printf("\t %s => not found\n", libname);
191 	}
192     }
193 }
194