1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <strings.h>
30 #include <dlfcn.h>
31 #include <debug.h>
32 #include <conv.h>
33 #include "msg.h"
34 #include "_libld.h"
35
36 /*
37 * dbg_setup() can be called a number of times. The typical use through
38 * LD_OPTIONS, results in dbg_setup() being called as the first argument to
39 * ld(1). It's also possible to pass debugging tokens through the compiler,
40 * for example -Wl,-Dlibs -Wl-Ddetail, in which case multiple dbg_setup()
41 * calls are made.
42 *
43 * A distinction is also made between diagnostics being requested before any
44 * other ld(1) options are read, or whether the debugging options occur
45 * between other options on the command line. In the latter case, the
46 * debugging options can be used to isolate diagnostics around one or more
47 * input files. The "phase" argument allows us to select which phase of
48 * dbg_setup() processing we should isolate ourselves to.
49 *
50 * dbg_print() can require the output filename for use in the diagnostics
51 * created. Save the address of the output filename pointer for this use.
52 */
53 static const char **Name = NULL;
54 static int Phase = 0;
55
56 /* Debug file output state */
57 static struct {
58 FILE *fptr; /* File to send debug output */
59 int close_needed; /* True if explicitly opened stream */
60 } dbg_ofile = {
61 stderr,
62 0
63 };
64
65
66 /*
67 * If there is an explicitly opened debug file, close it and reset the state.
68 */
69 void
dbg_cleanup(void)70 dbg_cleanup(void)
71 {
72 if (dbg_ofile.close_needed) {
73 (void) fclose(dbg_ofile.fptr);
74 dbg_ofile.close_needed = 0;
75 dbg_ofile.fptr = stderr;
76 }
77 }
78
79 /*
80 * Process debug tokens. Returns True (1) on success, and False (0)
81 * on failure.
82 */
83 int
dbg_setup(Ofl_desc * ofl,const char * options,int phase)84 dbg_setup(Ofl_desc *ofl, const char *options, int phase)
85 {
86 const char *ofile;
87
88 if (Phase == 0)
89 Phase = phase;
90 else if (Phase != phase)
91 return (1);
92
93 Name = &ofl->ofl_name;
94
95 /*
96 * Call the debugging setup routine to initialize the mask and
97 * debug function array.
98 */
99 if (Dbg_setup(DBG_CALLER_LD, options, dbg_desc, &ofile) == 0)
100 return (0);
101
102 /*
103 * If output= token was used, close the old file if necessary
104 * and open a new one if the file name is not NULL.
105 */
106 if (ofile) {
107 dbg_cleanup();
108 if (*ofile != '\0') {
109 FILE *fptr = fopen(ofile, MSG_ORIG(MSG_DBG_FOPEN_MODE));
110 if (fptr == NULL) {
111 int err = errno;
112
113 ld_eprintf(ofl, ERR_FATAL,
114 MSG_INTL(MSG_SYS_OPEN), ofile,
115 strerror(err));
116 return (0);
117 } else {
118 dbg_ofile.fptr = fptr;
119 dbg_ofile.close_needed = 1;
120 }
121 }
122 }
123
124 /*
125 * Now that the output file is established, identify the linker
126 * package, and generate help output if the user specified the
127 * debug help token.
128 */
129 Dbg_version();
130 if (dbg_desc->d_extra & DBG_E_HELP)
131 Dbg_help();
132
133 return (1);
134 }
135
136 /* PRINTFLIKE2 */
137 void
dbg_print(Lm_list * lml,const char * format,...)138 dbg_print(Lm_list *lml, const char *format, ...)
139 {
140 static char *prestr = NULL;
141 va_list args;
142
143 #if defined(lint)
144 /*
145 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
146 * Supress the lint error by making a dummy assignment.
147 */
148 lml = NULL;
149 #endif
150 /*
151 * Knock off any newline indicator to signify that a diagnostic has
152 * been processed.
153 */
154 dbg_desc->d_extra &= ~DBG_E_STDNL;
155
156 if (DBG_ISSNAME()) {
157 /*
158 * If the debugging options have requested each diagnostic line
159 * be prepended by a name create a prefix string.
160 */
161 if ((prestr == NULL) && *Name) {
162 const char *name, *cls;
163 size_t len;
164
165 /*
166 * Select the fullname or basename of the output file
167 * being created.
168 */
169 if (DBG_ISFNAME())
170 name = *Name;
171 else {
172 if ((name =
173 strrchr(*Name, '/')) == NULL)
174 name = *Name;
175 else
176 name++;
177 }
178 len = strlen(name) +
179 strlen(MSG_INTL(MSG_DBG_NAME_FMT)) + 1;
180
181 /*
182 * Add the output file class if required.
183 */
184 if (DBG_ISCLASS()) {
185 #if defined(_ELF64)
186 len += MSG_DBG_CLS64_FMT_SIZE;
187 cls = MSG_ORIG(MSG_DBG_CLS64_FMT);
188 #else
189 len += MSG_DBG_CLS32_FMT_SIZE;
190 cls = MSG_ORIG(MSG_DBG_CLS32_FMT);
191 #endif
192 }
193
194 /*
195 * Allocate a string to build the prefix.
196 */
197 if ((prestr = libld_malloc(len)) == NULL)
198 prestr = (char *)MSG_INTL(MSG_DBG_DFLT_FMT);
199 else {
200 (void) snprintf(prestr, len,
201 MSG_INTL(MSG_DBG_NAME_FMT), name);
202 if (DBG_ISCLASS())
203 (void) strcat(prestr, cls);
204 }
205 }
206 (void) fputs(prestr ? prestr : MSG_INTL(MSG_DBG_AOUT_FMT),
207 dbg_ofile.fptr);
208 } else
209 (void) fputs(MSG_INTL(MSG_DBG_DFLT_FMT), dbg_ofile.fptr);
210
211 if (DBG_ISTIME()) {
212 Conv_time_buf_t buf;
213 struct timeval new;
214
215 if (gettimeofday(&new, NULL) == 0) {
216 if (DBG_ISTTIME())
217 (void) fputs(conv_time(&DBG_TOTALTIME, &new,
218 &buf), stderr);
219 if (DBG_ISDTIME())
220 (void) fputs(conv_time(&DBG_DELTATIME, &new,
221 &buf), stderr);
222
223 DBG_DELTATIME = new;
224 }
225 }
226
227 va_start(args, format);
228 (void) vfprintf(dbg_ofile.fptr, format, args);
229 (void) fprintf(dbg_ofile.fptr, MSG_ORIG(MSG_STR_NL));
230 va_end(args);
231 }
232