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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <libintl.h>
28 #include <sys/varargs.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <alist.h>
33 #include <debug.h>
34 #include <_debug.h>
35 #include <msg.h>
36
37 /*
38 * Define a debug descriptor. Note, although this provides the default
39 * definition to which most users bind, ld.so.1 must provide its own definition,
40 * and thus interposition is expected. This item should be defined NODIRECT.
41 */
42 static Dbg_desc _dbg_desc = { 0, 0, NULL, { 0, 0 }, { 0, 0 } };
43 Dbg_desc *dbg_desc = &_dbg_desc;
44
45 int _Dbg_cnt = 0;
46
47 /*
48 * Debugging initialization and processing. The dbg_options[] array defines
49 * a set of option strings that can be specified using the -D flag or from an
50 * environment variable. For each option, a class is enabled in the d_class
51 * bit mask, or an extra flag is enabled in the d_extra bit mask.
52 */
53 static DBG_options _Dbg_options[] = { /* Options accepted by both linkers */
54 {MSG_ORIG(MSG_TOK_DETAIL), 0, DBG_E_DETAIL},
55 {MSG_ORIG(MSG_TOK_LONG), 0, DBG_E_LONG},
56 {MSG_ORIG(MSG_TOK_HELP), 0, DBG_E_HELP},
57 {MSG_ORIG(MSG_TOK_TTIME), 0, DBG_E_TTIME},
58 {MSG_ORIG(MSG_TOK_DTIME), 0, DBG_E_DTIME},
59
60 {MSG_ORIG(MSG_TOK_ALL), DBG_C_ALL & ~DBG_C_DEMANGLE, 0},
61 {MSG_ORIG(MSG_TOK_BASIC), DBG_C_BASIC, 0},
62 {MSG_ORIG(MSG_TOK_CAP), DBG_C_CAP, 0},
63 {MSG_ORIG(MSG_TOK_DEMANGLE), DBG_C_DEMANGLE, 0},
64 {MSG_ORIG(MSG_TOK_FILES), DBG_C_FILES, 0},
65 {MSG_ORIG(MSG_TOK_LIBS), DBG_C_LIBS, 0},
66 {MSG_ORIG(MSG_TOK_MOVE), DBG_C_MOVE, 0},
67 {MSG_ORIG(MSG_TOK_RELOC), DBG_C_RELOC, 0},
68 {MSG_ORIG(MSG_TOK_SYMBOLS), DBG_C_SYMBOLS, 0},
69 {MSG_ORIG(MSG_TOK_TLS), DBG_C_TLS, 0},
70 {MSG_ORIG(MSG_TOK_UNUSED), DBG_C_UNUSED, 0},
71 {MSG_ORIG(MSG_TOK_VERSIONS), DBG_C_VERSIONS, 0},
72 {NULL, 0, 0},
73 };
74
75 static DBG_options _Dbg_options_ld[] = { /* ld only options */
76 {MSG_ORIG(MSG_TOK_CLASS), 0, DBG_E_SNAME | DBG_E_CLASS},
77 {MSG_ORIG(MSG_TOK_FULLNAME), 0, DBG_E_SNAME | DBG_E_FNAME},
78 {MSG_ORIG(MSG_TOK_NAME), 0, DBG_E_SNAME},
79
80 {MSG_ORIG(MSG_TOK_ARGS), DBG_C_ARGS, 0},
81 {MSG_ORIG(MSG_TOK_ENTRY), DBG_C_ENTRY, 0},
82 {MSG_ORIG(MSG_TOK_GOT), DBG_C_GOT, 0},
83 {MSG_ORIG(MSG_TOK_MAP), DBG_C_MAP, 0},
84 {MSG_ORIG(MSG_TOK_SECTIONS), DBG_C_SECTIONS, 0},
85 {MSG_ORIG(MSG_TOK_SEGMENTS), DBG_C_SEGMENTS, 0},
86 {MSG_ORIG(MSG_TOK_STATS), DBG_C_STATS, 0},
87 {MSG_ORIG(MSG_TOK_STRTAB), DBG_C_STRTAB, 0},
88 {MSG_ORIG(MSG_TOK_SUPPORT), DBG_C_SUPPORT, 0},
89 {NULL, 0, 0},
90 };
91
92 static DBG_options _Dbg_options_rtld[] = { /* ld.so.1 only options */
93 {MSG_ORIG(MSG_TOK_AUDIT), DBG_C_AUDITING, 0},
94 {MSG_ORIG(MSG_TOK_BINDINGS), DBG_C_BINDINGS, 0},
95 {MSG_ORIG(MSG_TOK_DL), DBG_C_DL, 0},
96 {MSG_ORIG(MSG_TOK_INIT), DBG_C_INIT, 0},
97 {NULL, 0, 0},
98 };
99
100 /*
101 * Compare name to the options found in optarr. If one matches,
102 * update *dbp and return TRUE. Otherwise, FALSE.
103 */
104 static Boolean
process_options(const char * name,Boolean set,Dbg_desc * dbp,DBG_options * optarr)105 process_options(const char *name, Boolean set, Dbg_desc *dbp,
106 DBG_options *optarr)
107 {
108 DBG_options *opt;
109
110 for (opt = optarr; opt->o_name != NULL; opt++) {
111 if (strcmp(name, opt->o_name) != 0)
112 continue;
113
114 if (set == TRUE) {
115 if (opt->o_class)
116 dbp->d_class |= opt->o_class;
117 if (opt->o_extra)
118 dbp->d_extra |= opt->o_extra;
119 } else {
120 if (opt->o_class)
121 dbp->d_class &= ~(opt->o_class);
122 if (opt->o_extra)
123 dbp->d_extra &= ~(opt->o_extra);
124 }
125 return (TRUE);
126 }
127
128 return (FALSE);
129 }
130
131 /*
132 * Provide a debugging usage message
133 */
134 void
Dbg_help(void)135 Dbg_help(void)
136 {
137 Dbg_util_nl(0, DBG_NL_STD);
138 dbg_print(0, MSG_INTL(MSG_USE_R1_A));
139 dbg_print(0, MSG_INTL(MSG_USE_R1_B));
140 dbg_print(0, MSG_INTL(MSG_USE_R1_C));
141 dbg_print(0, MSG_INTL(MSG_USE_R1_D));
142 dbg_print(0, MSG_INTL(MSG_USE_R1_E));
143 dbg_print(0, MSG_INTL(MSG_USE_R1_F));
144 dbg_print(0, MSG_INTL(MSG_USE_R1_G));
145
146 Dbg_util_nl(0, DBG_NL_FRC);
147 dbg_print(0, MSG_INTL(MSG_USE_R2_A));
148 dbg_print(0, MSG_INTL(MSG_USE_R2_B));
149 dbg_print(0, MSG_INTL(MSG_USE_R2_C));
150 dbg_print(0, MSG_INTL(MSG_USE_R2_D));
151 dbg_print(0, MSG_INTL(MSG_USE_R2_E));
152 dbg_print(0, MSG_INTL(MSG_USE_R2_F));
153 dbg_print(0, MSG_INTL(MSG_USE_R2_G));
154 dbg_print(0, MSG_INTL(MSG_USE_R2_H));
155 dbg_print(0, MSG_INTL(MSG_USE_R2_I));
156 dbg_print(0, MSG_INTL(MSG_USE_R2_J));
157 dbg_print(0, MSG_INTL(MSG_USE_R2_K));
158 dbg_print(0, MSG_INTL(MSG_USE_R2_L));
159 dbg_print(0, MSG_INTL(MSG_USE_R2_M));
160 dbg_print(0, MSG_INTL(MSG_USE_R2_N));
161 dbg_print(0, MSG_INTL(MSG_USE_R2_O));
162 dbg_print(0, MSG_INTL(MSG_USE_R2_P));
163 dbg_print(0, MSG_INTL(MSG_USE_R2_Q));
164
165 Dbg_util_nl(0, DBG_NL_FRC);
166 dbg_print(0, MSG_INTL(MSG_USE_R2_R));
167 dbg_print(0, MSG_INTL(MSG_USE_R2_S));
168 dbg_print(0, MSG_INTL(MSG_USE_R2_T));
169 dbg_print(0, MSG_INTL(MSG_USE_R2_U));
170 dbg_print(0, MSG_INTL(MSG_USE_R2_V));
171 dbg_print(0, MSG_INTL(MSG_USE_R2_W));
172
173 Dbg_util_nl(0, DBG_NL_FRC);
174 dbg_print(0, MSG_INTL(MSG_USE_R3_A));
175 dbg_print(0, MSG_INTL(MSG_USE_R3_B));
176 dbg_print(0, MSG_INTL(MSG_USE_R3_C));
177 dbg_print(0, MSG_INTL(MSG_USE_R3_D));
178 dbg_print(0, MSG_INTL(MSG_USE_R3_E));
179 dbg_print(0, MSG_INTL(MSG_USE_R3_F));
180 dbg_print(0, MSG_INTL(MSG_USE_R3_G));
181
182 Dbg_util_nl(0, DBG_NL_FRC);
183 dbg_print(0, MSG_INTL(MSG_USE_R3_H));
184 dbg_print(0, MSG_INTL(MSG_USE_R3_F));
185 dbg_print(0, MSG_INTL(MSG_USE_R3_I));
186 dbg_print(0, MSG_INTL(MSG_USE_R3_J));
187 dbg_print(0, MSG_INTL(MSG_USE_R3_K));
188 dbg_print(0, MSG_INTL(MSG_USE_R3_L));
189 dbg_print(0, MSG_INTL(MSG_USE_R3_M));
190
191 Dbg_util_nl(0, DBG_NL_FRC);
192 dbg_print(0, MSG_INTL(MSG_USE_R3_N));
193
194 Dbg_util_nl(0, DBG_NL_FRC);
195 dbg_print(0, MSG_INTL(MSG_USE_HDR_DCT));
196 dbg_print(0, MSG_INTL(MSG_USE_HDR_BOTH));
197 dbg_print(0, MSG_INTL(MSG_USE_R4_A));
198 dbg_print(0, MSG_INTL(MSG_USE_R4_B));
199 dbg_print(0, MSG_INTL(MSG_USE_R4_B2));
200 dbg_print(0, MSG_INTL(MSG_USE_R4_C));
201 dbg_print(0, MSG_INTL(MSG_USE_R4_C2));
202 dbg_print(0, MSG_INTL(MSG_USE_R4_C3));
203 dbg_print(0, MSG_INTL(MSG_USE_R4_D));
204 dbg_print(0, MSG_INTL(MSG_USE_R4_E));
205 dbg_print(0, MSG_INTL(MSG_USE_R4_E2));
206 dbg_print(0, MSG_INTL(MSG_USE_R4_E3));
207 dbg_print(0, MSG_INTL(MSG_USE_R4_F));
208 dbg_print(0, MSG_INTL(MSG_USE_R4_F2));
209 dbg_print(0, MSG_INTL(MSG_USE_R4_F3));
210 dbg_print(0, MSG_INTL(MSG_USE_R4_F4));
211 dbg_print(0, MSG_INTL(MSG_USE_R4_F5));
212 dbg_print(0, MSG_INTL(MSG_USE_R4_F6));
213
214 Dbg_util_nl(0, DBG_NL_FRC);
215 dbg_print(0, MSG_INTL(MSG_USE_HDR_RTLD));
216 dbg_print(0, MSG_INTL(MSG_USE_R5_A));
217 dbg_print(0, MSG_INTL(MSG_USE_R5_A2));
218 dbg_print(0, MSG_INTL(MSG_USE_R5_A3));
219 dbg_print(0, MSG_INTL(MSG_USE_R5_A4));
220 dbg_print(0, MSG_INTL(MSG_USE_R5_A5));
221 dbg_print(0, MSG_INTL(MSG_USE_R5_A6));
222 dbg_print(0, MSG_INTL(MSG_USE_R5_A7));
223 dbg_print(0, MSG_INTL(MSG_USE_R5_A8));
224 dbg_print(0, MSG_INTL(MSG_USE_R5_A9));
225 dbg_print(0, MSG_INTL(MSG_USE_R5_A0));
226 dbg_print(0, MSG_INTL(MSG_USE_R5_B));
227 dbg_print(0, MSG_INTL(MSG_USE_R5_C));
228 dbg_print(0, MSG_INTL(MSG_USE_R5_D));
229 dbg_print(0, MSG_INTL(MSG_USE_R5_E));
230 dbg_print(0, MSG_INTL(MSG_USE_R5_F));
231
232 Dbg_util_nl(0, DBG_NL_FRC);
233 dbg_print(0, MSG_INTL(MSG_USE_HDR_LD));
234 dbg_print(0, MSG_INTL(MSG_USE_R6_A));
235 dbg_print(0, MSG_INTL(MSG_USE_R6_B));
236 dbg_print(0, MSG_INTL(MSG_USE_R6_C));
237 dbg_print(0, MSG_INTL(MSG_USE_R6_C2));
238
239 Dbg_util_nl(0, DBG_NL_FRC);
240 dbg_print(0, MSG_INTL(MSG_USE_HDR_CST));
241 dbg_print(0, MSG_INTL(MSG_USE_HDR_BOTH));
242 dbg_print(0, MSG_INTL(MSG_USE_R7_A));
243 dbg_print(0, MSG_INTL(MSG_USE_R7_B));
244 dbg_print(0, MSG_INTL(MSG_USE_R7_C));
245 dbg_print(0, MSG_INTL(MSG_USE_R7_D));
246 dbg_print(0, MSG_INTL(MSG_USE_R7_E));
247 dbg_print(0, MSG_INTL(MSG_USE_R7_F));
248 dbg_print(0, MSG_INTL(MSG_USE_R7_F2));
249 dbg_print(0, MSG_INTL(MSG_USE_R7_G));
250 dbg_print(0, MSG_INTL(MSG_USE_R7_H));
251 dbg_print(0, MSG_INTL(MSG_USE_R7_I));
252 dbg_print(0, MSG_INTL(MSG_USE_R7_I2));
253 dbg_print(0, MSG_INTL(MSG_USE_R7_J));
254 dbg_print(0, MSG_INTL(MSG_USE_R7_K));
255 dbg_print(0, MSG_INTL(MSG_USE_R7_K2));
256 dbg_print(0, MSG_INTL(MSG_USE_R7_L));
257
258 Dbg_util_nl(0, DBG_NL_FRC);
259 dbg_print(0, MSG_INTL(MSG_USE_HDR_RTLD));
260 dbg_print(0, MSG_INTL(MSG_USE_R8_A));
261 dbg_print(0, MSG_INTL(MSG_USE_R8_B));
262 dbg_print(0, MSG_INTL(MSG_USE_R8_B2));
263 dbg_print(0, MSG_INTL(MSG_USE_R8_C));
264 dbg_print(0, MSG_INTL(MSG_USE_R8_D));
265
266 Dbg_util_nl(0, DBG_NL_FRC);
267 dbg_print(0, MSG_INTL(MSG_USE_HDR_LD));
268 dbg_print(0, MSG_INTL(MSG_USE_R9_A));
269 dbg_print(0, MSG_INTL(MSG_USE_R9_B));
270 dbg_print(0, MSG_INTL(MSG_USE_R9_C));
271 dbg_print(0, MSG_INTL(MSG_USE_R9_D));
272 dbg_print(0, MSG_INTL(MSG_USE_R9_E));
273 dbg_print(0, MSG_INTL(MSG_USE_R9_F));
274 dbg_print(0, MSG_INTL(MSG_USE_R9_F2));
275 dbg_print(0, MSG_INTL(MSG_USE_R9_G));
276 dbg_print(0, MSG_INTL(MSG_USE_R9_H));
277 dbg_print(0, MSG_INTL(MSG_USE_R9_H2));
278 dbg_print(0, MSG_INTL(MSG_USE_R9_I));
279
280 Dbg_util_nl(0, DBG_NL_FRC);
281 }
282
283 /*
284 * Provide a debugging message showing the version of the linker package
285 */
286 void
Dbg_version(void)287 Dbg_version(void)
288 {
289 Dbg_util_nl(0, DBG_NL_STD);
290 dbg_print(0, MSG_ORIG(MSG_STR_LDVER), link_ver_string);
291 Dbg_util_nl(0, DBG_NL_STD);
292 }
293
294 /*
295 * Messaging support - funnel everything through dgettext() as this provides
296 * the real binding to libc.
297 */
298 const char *
_liblddbg_msg(Msg mid)299 _liblddbg_msg(Msg mid)
300 {
301 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
302 }
303
304 /*
305 * Given a name starting with "lmid", finish processing it. Return TRUE
306 * if a valid lmid token was seen, and FALSE for any error.
307 *
308 * exit:
309 * On failure, returns FALSE, indicating a syntax error
310 *
311 * On success:
312 * - Appropriate flags in dbg->d_extra have been set
313 * - Any link-map list names specified have been added to
314 * d_list, for the rtld dbg_print() to compare against
315 * link-map list names.
316 * - TRUE is returned.
317 */
318 static Boolean
process_lmid(char * name,Dbg_desc * dbp)319 process_lmid(char *name, Dbg_desc *dbp)
320 {
321 /*
322 * "lmid" can have an optional argument. Allowed values are "all",
323 * "alt[0-9]+", "base", or "ldso". Alt has a variable ending, but
324 * we can use process_options() to handle the other three.
325 */
326 static DBG_options options_lmid[] = {
327 {MSG_ORIG(MSG_TOK_LMID_ALL), 0, DBG_E_LMID_ALL},
328 {MSG_ORIG(MSG_TOK_LMID_BASE), 0, DBG_E_LMID_BASE},
329 {MSG_ORIG(MSG_TOK_LMID_LDSO), 0, DBG_E_LMID_LDSO},
330 {NULL, 0, 0},
331 };
332
333 Dbg_desc tmp_db;
334 const char *lmid_opt;
335
336 /* If it's a plain "lmid", we can set the flag and return now */
337 if (name[MSG_TOK_LMID_SIZE] == '\0') {
338 dbp->d_extra |= DBG_E_LMID;
339 return (TRUE);
340 }
341
342 /* If there's no value, its an error */
343 if (conv_strproc_extract_value(name, MSG_TOK_LMID_SIZE,
344 CONV_SPEXV_F_UCASE, &lmid_opt) == 0)
345 return (FALSE);
346
347 /*
348 * ALL, BASE, or LDSO?
349 */
350 tmp_db.d_extra = 0;
351 if (process_options(lmid_opt, TRUE, &tmp_db, options_lmid)) {
352 /*
353 * If BASE, and we haven't already seen it, add it to the
354 * rtld name matching list. For the others, setting the
355 * e_extra bit suffices.
356 */
357 if (((tmp_db.d_extra & DBG_E_LMID_BASE) != 0) &&
358 ((dbp->d_extra & DBG_E_LMID_BASE) == 0) &&
359 (aplist_append(&dbp->d_list, MSG_ORIG(MSG_TOK_LMID_BASE),
360 AL_CNT_DEBUG) == NULL))
361 return (FALSE);
362
363 /* Add the resulting flags into the callers descriptor */
364 dbp->d_extra |= DBG_E_LMID | tmp_db.d_extra;
365 return (TRUE);
366 }
367
368 /*
369 * ALT?
370 */
371 if (strncmp(lmid_opt, MSG_ORIG(MSG_TOK_LMID_ALT),
372 MSG_TOK_LMID_ALT_SIZE) == 0) {
373 const char *tail = lmid_opt + MSG_TOK_LMID_ALT_SIZE;
374
375 /* 'ALT' without a # means "all alternative link-map lists" */
376 if (*tail == '\0') {
377 dbp->d_extra |= DBG_E_LMID | DBG_E_LMID_ALT;
378 return (TRUE);
379 }
380
381 /*
382 * It is ALT[0-9]+. Make sure the characters following 'ALT'
383 * are numbers, and then add it to the rtld name matching list.
384 */
385 for (; *tail; tail++)
386 if ((*tail < '0') || (*tail > '9'))
387 return (FALSE);
388
389 if (aplist_append(&dbp->d_list, lmid_opt, AL_CNT_DEBUG) == NULL)
390 return (FALSE);
391 dbp->d_extra |= DBG_E_LMID;
392 return (TRUE);
393 }
394
395 /* It's nothing we recognize */
396 return (FALSE);
397 }
398
399 /*
400 * Validate and enable the appropriate debugging classes.
401 *
402 * entry:
403 * string - String to be analyzed for debugging options
404 * dbp - Pointer to debug descriptor to be initialized
405 * outfile_ret - NULL, or pointer to receive result of 'output='
406 * token. A NULL value means that the 'output=' token
407 * is not accepted. A non-NULL value means that it is.
408 *
409 * exit:
410 * On failure, False (0) is returned.
411 *
412 * On success, string has been parsed, and the descriptor referenced
413 * by dbp has been initialized. If outfile is non-NULL, *outfile will
414 * be set to NULL if the 'output=' token is not present, and to the
415 * user supplied string otherwise. True (1) is returned.
416 */
417 int
Dbg_setup(dbg_setup_caller_t caller,const char * string,Dbg_desc * dbp,const char ** outfile)418 Dbg_setup(dbg_setup_caller_t caller, const char *string, Dbg_desc *dbp,
419 const char **outfile)
420 {
421 char *name, *_name; /* buffer in which to perform */
422 /* strtok_r() operations. */
423 char *lasts;
424 const char *delimit = MSG_ORIG(MSG_STR_DELIMIT);
425
426 /*
427 * Clear the help flags --- these items only apply for a single
428 * call to Dbg_setup().
429 */
430 dbp->d_extra &= ~(DBG_E_HELP | DBG_E_HELP_EXIT);
431
432 if ((_name = (char *)malloc(strlen(string) + 1)) == NULL)
433 return (0);
434 (void) strcpy(_name, string);
435
436 if (outfile)
437 *outfile = NULL; /* No output file yet */
438
439 /*
440 * The token should be of the form "-Dtok,tok,tok,...". Separate the
441 * pieces and build up the appropriate mask, unrecognized options are
442 * flagged.
443 */
444 if ((name = strtok_r(_name, delimit, &lasts)) != NULL) {
445 do {
446 Boolean set;
447
448 /* Remove leading and trailing whitespace */
449 name = conv_strproc_trim(name);
450
451 if (name[0] == '!') {
452 set = FALSE;
453 name++;
454 } else
455 set = TRUE;
456
457 if (*name == '\0')
458 continue; /* Skip null token */
459
460 /*
461 * First, determine if the token represents a class or
462 * extra.
463 */
464 if (process_options(name, set, dbp, _Dbg_options))
465 continue;
466 switch (caller) {
467 case DBG_CALLER_LD: /* ld only tokens */
468 if (process_options(name, set, dbp,
469 _Dbg_options_ld))
470 continue;
471 break;
472 case DBG_CALLER_RTLD: /* rtld only tokens */
473 if (process_options(name, set, dbp,
474 _Dbg_options_rtld))
475 continue;
476 break;
477 }
478
479 /* The remaining options do not accept negation */
480 if (!set) {
481 dbg_print(0, MSG_INTL(MSG_USE_CNTNEGOPT), name);
482 continue;
483 }
484
485 /*
486 * Is it an 'output=' token? This item is a special
487 * case because it depends on the presence of
488 * a non-NULL outfile argument, and because the
489 * part following the '=' is variable.
490 */
491 if ((outfile != NULL) &&
492 strncmp(name, MSG_ORIG(MSG_TOK_OUTFILE),
493 MSG_TOK_OUTFILE_SIZE) == 0) {
494 if (conv_strproc_extract_value(name,
495 MSG_TOK_OUTFILE_SIZE, 0, outfile))
496 continue;
497 }
498
499 /*
500 * Only the rtld "lmid" token is left.
501 */
502 if ((caller == DBG_CALLER_RTLD) && (strncmp(name,
503 MSG_ORIG(MSG_TOK_LMID), MSG_TOK_LMID_SIZE) == 0) &&
504 process_lmid(name, dbp))
505 continue;
506
507 /* If we make it here, the token is not understood */
508 dbg_print(0, MSG_INTL(MSG_USE_UNRECOG), name);
509
510 } while ((name = strtok_r(NULL, delimit, &lasts)) != NULL);
511 }
512
513 /*
514 * If the debug help option was specified and this is the only debug
515 * class, return an indication that the user should exit.
516 */
517 if ((_Dbg_cnt++ == 0) && (dbp->d_extra & DBG_E_HELP) &&
518 (dbp->d_class == 0))
519 dbp->d_extra |= DBG_E_HELP_EXIT;
520
521 return (1);
522 }
523
524 /*
525 * Define our own printing routine. This provides a basic fallback, as ld(1)
526 * and ld.so.1(1) provide their own routines that augment their diagnostic
527 * output, and direct the output to stderr. This item should be defined
528 * NODIRECT.
529 */
530 /* PRINTFLIKE2 */
531 void
dbg_print(Lm_list * lml,const char * format,...)532 dbg_print(Lm_list *lml, const char *format, ...)
533 {
534 va_list ap;
535
536 #if defined(lint)
537 /*
538 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
539 * Supress the lint error by making a dummy assignment.
540 */
541 lml = 0;
542 #endif
543 va_start(ap, format);
544 (void) vprintf(format, ap);
545 (void) printf(MSG_ORIG(MSG_STR_NL));
546 va_end(ap);
547 }
548
549 /*
550 * Return an internationalized state transition string. These are used by
551 * various debugging output.
552 */
553 const char *
Dbg_state_str(dbg_state_t type)554 Dbg_state_str(dbg_state_t type)
555 {
556 static const Msg state[DBG_STATE_NUM] = {
557 MSG_STR_ADD, /* MSG_INTL(MSG_STR_ADD) */
558 MSG_STR_CURRENT, /* MSG_INTL(MSG_STR_CURRENT) */
559 MSG_STR_EXCLUDE, /* MSG_INTL(MSG_STR_EXCLUDE) */
560 MSG_STR_IGNORE, /* MSG_INTL(MSG_STR_IGNORE) */
561 MSG_STR_MOD_BEFORE, /* MSG_INTL(MSG_STR_MOD_BEFORE) */
562 MSG_STR_MOD_AFTER, /* MSG_INTL(MSG_STR_MOD_AFTER) */
563 MSG_STR_NEW, /* MSG_INTL(MSG_STR_NEW) */
564 MSG_STR_NEW_IMPLICIT, /* MSG_INTL(MSG_STR_NEW_IMPLICIT) */
565 MSG_STR_RESET, /* MSG_INTL(MSG_STR_RESET) */
566 MSG_STR_ORIGINAL, /* MSG_INTL(MSG_STR_ORIGINAL) */
567 MSG_STR_RESOLVED, /* MSG_INTL(MSG_STR_RESOLVED) */
568 };
569 #if DBG_STATE_NUM != (DBG_STATE_RESOLVED + 1)
570 #error DBG_SEG_NUM has changed. Update segtype[]
571 #endif
572
573 assert(type < DBG_STATE_NUM);
574 return (MSG_INTL(state[type]));
575 }
576