* elf/dl-misc.c (_dl_sysdep_read_whole_file): We really don't need
[platform/upstream/glibc.git] / elf / dl-misc.c
1 /* Miscellaneous support functions for dynamic linker
2    Copyright (C) 1997-2004, 2006, 2007 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <fcntl.h>
22 #include <ldsodefs.h>
23 #include <limits.h>
24 #include <link.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/mman.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/uio.h>
33 #include <sysdep.h>
34 #include <stdio-common/_itoa.h>
35 #include <bits/libc-lock.h>
36
37 #ifndef MAP_ANON
38 /* This is the only dl-sysdep.c function that is actually needed at run-time
39    by _dl_map_object.  */
40
41 int
42 _dl_sysdep_open_zero_fill (void)
43 {
44   return __open ("/dev/zero", O_RDONLY);
45 }
46 #endif
47
48 /* Read the whole contents of FILE into new mmap'd space with given
49    protections.  *SIZEP gets the size of the file.  On error MAP_FAILED
50    is returned.  */
51
52 void *
53 internal_function
54 _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
55 {
56   void *result = MAP_FAILED;
57   struct stat64 st;
58   int oflags = O_RDONLY;
59 #ifdef O_NOATIME
60   oflags |= O_NOATIME;
61 #endif
62   int fd = __open (file, oflags);
63   if (fd >= 0)
64     {
65       if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
66         {
67           *sizep = st.st_size;
68
69           /* No need to map the file if it is empty.  */
70           if (*sizep != 0)
71             /* Map a copy of the file contents.  */
72             result = __mmap (NULL, *sizep, prot,
73 #ifdef MAP_COPY
74                              MAP_COPY
75 #else
76                              MAP_PRIVATE
77 #endif
78 #ifdef MAP_FILE
79                              | MAP_FILE
80 #endif
81                              , fd, 0);
82         }
83       __close (fd);
84     }
85   return result;
86 }
87
88
89 /* Bare-bones printf implementation.  This function only knows about
90    the formats and flags needed and can handle only up to 64 stripes in
91    the output.  */
92 static void
93 _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
94 {
95 # define NIOVMAX 64
96   struct iovec iov[NIOVMAX];
97   int niov = 0;
98   pid_t pid = 0;
99   char pidbuf[12];
100
101   while (*fmt != '\0')
102     {
103       const char *startp = fmt;
104
105       if (tag_p > 0)
106         {
107           /* Generate the tag line once.  It consists of the PID and a
108              colon followed by a tab.  */
109           if (pid == 0)
110             {
111               char *p;
112               pid = __getpid ();
113               assert (pid >= 0 && sizeof (pid_t) <= 4);
114               p = _itoa (pid, &pidbuf[10], 10, 0);
115               while (p > pidbuf)
116                 *--p = ' ';
117               pidbuf[10] = ':';
118               pidbuf[11] = '\t';
119             }
120
121           /* Append to the output.  */
122           assert (niov < NIOVMAX);
123           iov[niov].iov_len = 12;
124           iov[niov++].iov_base = pidbuf;
125
126           /* No more tags until we see the next newline.  */
127           tag_p = -1;
128         }
129
130       /* Skip everything except % and \n (if tags are needed).  */
131       while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
132         ++fmt;
133
134       /* Append constant string.  */
135       assert (niov < NIOVMAX);
136       if ((iov[niov].iov_len = fmt - startp) != 0)
137         iov[niov++].iov_base = (char *) startp;
138
139       if (*fmt == '%')
140         {
141           /* It is a format specifier.  */
142           char fill = ' ';
143           int width = -1;
144           int prec = -1;
145 #if LONG_MAX != INT_MAX
146           int long_mod = 0;
147 #endif
148
149           /* Recognize zero-digit fill flag.  */
150           if (*++fmt == '0')
151             {
152               fill = '0';
153               ++fmt;
154             }
155
156           /* See whether with comes from a parameter.  Note that no other
157              way to specify the width is implemented.  */
158           if (*fmt == '*')
159             {
160               width = va_arg (arg, int);
161               ++fmt;
162             }
163
164           /* Handle precision.  */
165           if (*fmt == '.' && fmt[1] == '*')
166             {
167               prec = va_arg (arg, int);
168               fmt += 2;
169             }
170
171           /* Recognize the l modifier.  It is only important on some
172              platforms where long and int have a different size.  We
173              can use the same code for size_t.  */
174           if (*fmt == 'l' || *fmt == 'Z')
175             {
176 #if LONG_MAX != INT_MAX
177               long_mod = 1;
178 #endif
179               ++fmt;
180             }
181
182           switch (*fmt)
183             {
184               /* Integer formatting.  */
185             case 'u':
186             case 'x':
187               {
188                 /* We have to make a difference if long and int have a
189                    different size.  */
190 #if LONG_MAX != INT_MAX
191                 unsigned long int num = (long_mod
192                                          ? va_arg (arg, unsigned long int)
193                                          : va_arg (arg, unsigned int));
194 #else
195                 unsigned long int num = va_arg (arg, unsigned int);
196 #endif
197                 /* We use alloca() to allocate the buffer with the most
198                    pessimistic guess for the size.  Using alloca() allows
199                    having more than one integer formatting in a call.  */
200                 char *buf = (char *) alloca (3 * sizeof (unsigned long int));
201                 char *endp = &buf[3 * sizeof (unsigned long int)];
202                 char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
203
204                 /* Pad to the width the user specified.  */
205                 if (width != -1)
206                   while (endp - cp < width)
207                     *--cp = fill;
208
209                 iov[niov].iov_base = cp;
210                 iov[niov].iov_len = endp - cp;
211                 ++niov;
212               }
213               break;
214
215             case 's':
216               /* Get the string argument.  */
217               iov[niov].iov_base = va_arg (arg, char *);
218               iov[niov].iov_len = strlen (iov[niov].iov_base);
219               if (prec != -1)
220                 iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
221               ++niov;
222               break;
223
224             case '%':
225               iov[niov].iov_base = (void *) fmt;
226               iov[niov].iov_len = 1;
227               ++niov;
228               break;
229
230             default:
231               assert (! "invalid format specifier");
232             }
233           ++fmt;
234         }
235       else if (*fmt == '\n')
236         {
237           /* See whether we have to print a single newline character.  */
238           if (fmt == startp)
239             {
240               iov[niov].iov_base = (char *) startp;
241               iov[niov++].iov_len = 1;
242             }
243           else
244             /* No, just add it to the rest of the string.  */
245             ++iov[niov - 1].iov_len;
246
247           /* Next line, print a tag again.  */
248           tag_p = 1;
249           ++fmt;
250         }
251     }
252
253   /* Finally write the result.  */
254 #ifdef HAVE_INLINED_SYSCALLS
255   INTERNAL_SYSCALL_DECL (err);
256   INTERNAL_SYSCALL (writev, err, 3, fd, &iov, niov);
257 #elif RTLD_PRIVATE_ERRNO
258   /* We have to take this lock just to be sure we don't clobber the private
259      errno when it's being used by another thread that cares about it.
260      Yet we must be sure not to try calling the lock functions before
261      the thread library is fully initialized.  */
262   if (__builtin_expect (INTUSE (_dl_starting_up), 0))
263     __writev (fd, iov, niov);
264   else
265     {
266       __rtld_lock_lock_recursive (GL(dl_load_lock));
267       __writev (fd, iov, niov);
268       __rtld_lock_unlock_recursive (GL(dl_load_lock));
269     }
270 #else
271   __writev (fd, iov, niov);
272 #endif
273 }
274
275
276 /* Write to debug file.  */
277 void
278 _dl_debug_printf (const char *fmt, ...)
279 {
280   va_list arg;
281
282   va_start (arg, fmt);
283   _dl_debug_vdprintf (GLRO(dl_debug_fd), 1, fmt, arg);
284   va_end (arg);
285 }
286
287
288 /* Write to debug file but don't start with a tag.  */
289 void
290 _dl_debug_printf_c (const char *fmt, ...)
291 {
292   va_list arg;
293
294   va_start (arg, fmt);
295   _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, arg);
296   va_end (arg);
297 }
298
299
300 /* Write the given file descriptor.  */
301 void
302 _dl_dprintf (int fd, const char *fmt, ...)
303 {
304   va_list arg;
305
306   va_start (arg, fmt);
307   _dl_debug_vdprintf (fd, 0, fmt, arg);
308   va_end (arg);
309 }
310
311
312 /* Test whether given NAME matches any of the names of the given object.  */
313 int
314 internal_function
315 _dl_name_match_p (const char *name, const struct link_map *map)
316 {
317   if (strcmp (name, map->l_name) == 0)
318     return 1;
319
320   struct libname_list *runp = map->l_libname;
321
322   while (runp != NULL)
323     if (strcmp (name, runp->name) == 0)
324       return 1;
325     else
326       runp = runp->next;
327
328   return 0;
329 }