ab883acb3cbb62bfdb38cc1ed9c990cbf546f1df
[platform/upstream/glibc.git] / elf / dl-misc.c
1 /* Miscellaneous support functions for dynamic linker
2    Copyright (C) 1997,1998,1999,2000,2001,2002 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 <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.  On error MAP_FAILED
48    is returned.  */
49
50 void *
51 internal_function
52 _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
53 {
54   void *result = MAP_FAILED;
55   struct stat64 st;
56   int fd = __open (file, O_RDONLY);
57   if (fd >= 0)
58     {
59       if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
60         {
61           *sizep = st.st_size;
62
63           /* No need to map the file if it is empty.  */
64           if (*sizep != 0)
65             /* Map a copy of the file contents.  */
66             result = __mmap (NULL, *sizep, prot,
67 #ifdef MAP_COPY
68                              MAP_COPY
69 #else
70                              MAP_PRIVATE
71 #endif
72 #ifdef MAP_FILE
73                              | MAP_FILE
74 #endif
75                              , fd, 0);
76         }
77       __close (fd);
78     }
79   return result;
80 }
81
82
83 /* Bare-bone printf implementation.  This function only knows about
84    the formats and flags needed and can handle only up to 64 stripes in
85    the output.  */
86 static void
87 _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
88 {
89   const int niovmax = 64;
90   struct iovec iov[niovmax];
91   int niov = 0;
92   pid_t pid = 0;
93   char pidbuf[7];
94
95   while (*fmt != '\0')
96     {
97       const char *startp = fmt;
98
99       if (tag_p > 0)
100         {
101           /* Generate the tag line once.  It consists of the PID and a
102              colon followed by a tab.  */
103           if (pid == 0)
104             {
105               char *p;
106               pid = __getpid ();
107               assert (pid >= 0 && pid < 100000);
108               p = _itoa (pid, &pidbuf[5], 10, 0);
109               while (p > pidbuf)
110                 *--p = '0';
111               pidbuf[5] = ':';
112               pidbuf[6] = '\t';
113             }
114
115           /* Append to the output.  */
116           assert (niov < niovmax);
117           iov[niov].iov_len = 7;
118           iov[niov++].iov_base = pidbuf;
119
120           /* No more tags until we see the next newline.  */
121           tag_p = -1;
122         }
123
124       /* Skip everything except % and \n (if tags are needed).  */
125       while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
126         ++fmt;
127
128       /* Append constant string.  */
129       assert (niov < niovmax);
130       if ((iov[niov].iov_len = fmt - startp) != 0)
131         iov[niov++].iov_base = (char *) startp;
132
133       if (*fmt == '%')
134         {
135           /* It is a format specifier.  */
136           char fill = ' ';
137           int width = -1;
138 #if LONG_MAX != INT_MAX
139           int long_mod = 0;
140 #endif
141
142           /* Recognize zero-digit fill flag.  */
143           if (*++fmt == '0')
144             {
145               fill = '0';
146               ++fmt;
147             }
148
149           /* See whether with comes from a parameter.  Note that no other
150              way to specify the width is implemented.  */
151           if (*fmt == '*')
152             {
153               width = va_arg (arg, int);
154               ++fmt;
155             }
156
157           /* Recognize the l modifier.  It is only important on some
158              platforms where long and int have a different size.  We
159              can use the same code for size_t.  */
160           if (*fmt == 'l' || *fmt == 'Z')
161             {
162 #if LONG_MAX != INT_MAX
163               long_mod = 1;
164 #endif
165               ++fmt;
166             }
167
168           switch (*fmt)
169             {
170               /* Integer formatting.  */
171             case 'u':
172             case 'x':
173               {
174                 /* We have to make a difference if long and int have a
175                    different size.  */
176 #if LONG_MAX != INT_MAX
177                 unsigned long int num = (long_mod
178                                          ? va_arg (arg, unsigned long int)
179                                          : va_arg (arg, unsigned int));
180 #else
181                 unsigned long int num = va_arg (arg, unsigned int);
182 #endif
183                 /* We use alloca() to allocate the buffer with the most
184                    pessimistic guess for the size.  Using alloca() allows
185                    having more than one integer formatting in a call.  */
186                 char *buf = (char *) alloca (3 * sizeof (unsigned long int));
187                 char *endp = &buf[3 * sizeof (unsigned long int)];
188                 char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
189
190                 /* Pad to the width the user specified.  */
191                 if (width != -1)
192                   while (endp - cp < width)
193                     *--cp = fill;
194
195                 iov[niov].iov_base = cp;
196                 iov[niov].iov_len = endp - cp;
197                 ++niov;
198               }
199               break;
200
201             case 's':
202               /* Get the string argument.  */
203               iov[niov].iov_base = va_arg (arg, char *);
204               iov[niov].iov_len = strlen (iov[niov].iov_base);
205               ++niov;
206               break;
207
208             case '%':
209               iov[niov].iov_base = (void *) fmt;
210               iov[niov].iov_len = 1;
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 (GL(dl_debug_fd), 1, fmt, arg);
250   va_end (arg);
251 }
252 INTDEF(_dl_debug_printf)
253
254
255 /* Write to debug file but don't start with a tag.  */
256 void
257 _dl_debug_printf_c (const char *fmt, ...)
258 {
259   va_list arg;
260
261   va_start (arg, fmt);
262   _dl_debug_vdprintf (GL(dl_debug_fd), -1, fmt, arg);
263   va_end (arg);
264 }
265
266
267 /* Write the given file descriptor.  */
268 void
269 _dl_dprintf (int fd, const char *fmt, ...)
270 {
271   va_list arg;
272
273   va_start (arg, fmt);
274   _dl_debug_vdprintf (fd, 0, fmt, arg);
275   va_end (arg);
276 }