Update.
[platform/upstream/glibc.git] / elf / dl-misc.c
1 /* Miscellaneous support functions for dynamic linker
2    Copyright (C) 1997, 1998, 1999, 2000, 2001 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 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 <stdio-common/_itoa.h>
34
35 #ifndef MAP_ANON
36 /* This is the only dl-sysdep.c function that is actually needed at run-time
37    by _dl_map_object.  */
38
39 int
40 _dl_sysdep_open_zero_fill (void)
41 {
42   return __open ("/dev/zero", O_RDONLY);
43 }
44 #endif
45
46 /* Read the whole contents of FILE into new mmap'd space with given
47    protections.  *SIZEP gets the size of the file.  */
48
49 void *
50 internal_function
51 _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
52 {
53   void *result;
54   struct stat64 st;
55   int fd = __open (file, O_RDONLY);
56   if (fd < 0)
57     return NULL;
58   if (__fxstat64 (_STAT_VER, fd, &st) < 0
59       /* No need to map the file if it is empty.  */
60       || st.st_size == 0)
61     result = NULL;
62   else
63     {
64       /* Map a copy of the file contents.  */
65       result = __mmap (0, st.st_size, prot,
66 #ifdef MAP_COPY
67                        MAP_COPY
68 #else
69                        MAP_PRIVATE
70 #endif
71 #ifdef MAP_FILE
72                        | MAP_FILE
73 #endif
74                        , fd, 0);
75       if (result == MAP_FAILED)
76         result = NULL;
77       else
78         *sizep = st.st_size;
79     }
80   __close (fd);
81   return result;
82 }
83
84
85 /* Descriptor to write debug messages to.  */
86 int _dl_debug_fd = 2;
87
88
89 /* Bare-bone 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   const int niovmax = 64;
96   struct iovec iov[niovmax];
97   int niov = 0;
98   pid_t pid = 0;
99   char pidbuf[7];
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 && pid < 100000);
114               p = _itoa_word (pid, &pidbuf[5], 10, 0);
115               while (p > pidbuf)
116                 *--p = '0';
117               pidbuf[5] = ':';
118               pidbuf[6] = '\t';
119             }
120
121           /* Append to the output.  */
122           assert (niov < niovmax);
123           iov[niov].iov_len = 7;
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 #if LONG_MAX != INT_MAX
145           int long_mod = 0;
146 #endif
147
148           /* Recognize zero-digit fill flag.  */
149           if (*++fmt == '0')
150             {
151               fill = '0';
152               ++fmt;
153             }
154
155           /* See whether with comes from a parameter.  Note that no other
156              way to specify the width is implemented.  */
157           if (*fmt == '*')
158             {
159               width = va_arg (arg, int);
160               ++fmt;
161             }
162
163           /* Recognize the l modifier.  It is only important on some
164              platforms where long and int have a different size.  We
165              can use the same code for size_t.  */
166           if (*fmt == 'l' || *fmt == 'Z')
167             {
168 #if LONG_MAX != INT_MAX
169               long_mod = 1;
170 #endif
171               ++fmt;
172             }
173
174           switch (*fmt)
175             {
176               /* Integer formatting.  */
177             case 'u':
178             case 'x':
179               {
180                 /* We have to make a difference if long and int have a
181                    different size.  */
182 #if LONG_MAX != INT_MAX
183                 unsigned long int num = (long_mod
184                                          ? va_arg (arg, unsigned long int);
185                                          : va_arg (arg, unsigned int));
186 #else
187                 unsigned long int num = va_arg (arg, unsigned int);
188 #endif
189                 /* We use alloca() to allocate the buffer with the most
190                    pessimistic guess for the size.  Using alloca() allows
191                    having more than one integer formatting in a call.  */
192                 char *buf = (char *) alloca (3 * sizeof (unsigned long int));
193                 char *endp = &buf[3 * sizeof (unsigned long int)];
194                 char *cp = _itoa_word (num, endp, *fmt == 'x' ? 16 : 10, 0);
195
196                 /* Pad to the width the user specified.  */
197                 if (width != -1)
198                   while (endp - cp < width)
199                     *--cp = fill;
200
201                 iov[niov].iov_base = cp;
202                 iov[niov].iov_len = endp - cp;
203                 ++niov;
204               }
205               break;
206
207             case 's':
208               /* Get the string argument.  */
209               iov[niov].iov_base = va_arg (arg, char *);
210               iov[niov].iov_len = strlen (iov[niov].iov_base);
211               ++niov;
212               break;
213
214             default:
215               assert (! "invalid format specifier");
216             }
217           ++fmt;
218         }
219       else if (*fmt == '\n')
220         {
221           /* See whether we have to print a single newline character.  */
222           if (fmt == startp)
223             {
224               iov[niov].iov_base = (char *) startp;
225               iov[niov++].iov_len = 1;
226             }
227           else
228             /* No, just add it to the rest of the string.  */
229             ++iov[niov - 1].iov_len;
230
231           /* Next line, print a tag again.  */
232           tag_p = 1;
233           ++fmt;
234         }
235     }
236
237   /* Finally write the result.  */
238   __writev (fd, iov, niov);
239 }
240
241
242 /* Write to debug file.  */
243 void
244 _dl_debug_printf (const char *fmt, ...)
245 {
246   va_list arg;
247
248   va_start (arg, fmt);
249   _dl_debug_vdprintf (_dl_debug_fd, 1, fmt, arg);
250   va_end (arg);
251 }
252
253
254 /* Write to debug file but don't start with a tag.  */
255 void
256 _dl_debug_printf_c (const char *fmt, ...)
257 {
258   va_list arg;
259
260   va_start (arg, fmt);
261   _dl_debug_vdprintf (_dl_debug_fd, -1, fmt, arg);
262   va_end (arg);
263 }
264
265
266 /* Write the given file descriptor.  */
267 void
268 _dl_dprintf (int fd, const char *fmt, ...)
269 {
270   va_list arg;
271
272   va_start (arg, fmt);
273   _dl_debug_vdprintf (fd, 0, fmt, arg);
274   va_end (arg);
275 }