17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 23*69112eddSAli Bahrami * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/stat.h> 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <fcntl.h> 327c478bd9Sstevel@tonic-gate #include <stdarg.h> 337c478bd9Sstevel@tonic-gate #include <dlfcn.h> 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <thread.h> 375aefb655Srie #include <debug.h> 382017c965SRod Evans #include <conv.h> 397c478bd9Sstevel@tonic-gate #include "_rtld.h" 407c478bd9Sstevel@tonic-gate #include "_elf.h" 417c478bd9Sstevel@tonic-gate #include "msg.h" 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate static int dbg_fd; /* debugging output file descriptor */ 457c478bd9Sstevel@tonic-gate static dev_t dbg_dev; 46cb511613SAli Bahrami static rtld_ino_t dbg_ino; 47e23c41c9SAli Bahrami static int dbg_add_pid; /* True to add pid to debug file name */ 487c478bd9Sstevel@tonic-gate static pid_t pid; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * Enable diagnostic output. All debugging functions reside in the linker 527c478bd9Sstevel@tonic-gate * debugging library liblddbg.so which is lazy loaded when required. 537c478bd9Sstevel@tonic-gate */ 54e23c41c9SAli Bahrami int 555aefb655Srie dbg_setup(const char *options, Dbg_desc *dbp) 567c478bd9Sstevel@tonic-gate { 57cb511613SAli Bahrami rtld_stat_t status; 58e23c41c9SAli Bahrami const char *ofile; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate /* 617c478bd9Sstevel@tonic-gate * If we're running secure, only allow debugging if ld.so.1 itself is 627c478bd9Sstevel@tonic-gate * owned by root and has its mode setuid. Fail silently. 637c478bd9Sstevel@tonic-gate */ 643dbfc803SRod Evans if ((rtld_flags & RT_FL_SECURE) && (is_rtld_setuid() == 0)) 65e23c41c9SAli Bahrami return (1); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * As Dbg_setup() will effectively lazy load the necessary support 697c478bd9Sstevel@tonic-gate * libraries, make sure ld.so.1 is initialized for plt relocations. 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate if (elf_rtld_load() == 0) 72e23c41c9SAli Bahrami return (1); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * Call the debugging setup routine. This function verifies the 767c478bd9Sstevel@tonic-gate * debugging tokens provided and returns a mask indicating the debugging 777c478bd9Sstevel@tonic-gate * categories selected. The mask effectively enables calls to the 787c478bd9Sstevel@tonic-gate * debugging library. 797c478bd9Sstevel@tonic-gate */ 80e23c41c9SAli Bahrami if (Dbg_setup(DBG_CALLER_RTLD, options, dbp, &ofile) == 0) 81e23c41c9SAli Bahrami return (0); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 84dde769a2SRod Evans * Obtain the process id. 85dde769a2SRod Evans */ 86dde769a2SRod Evans pid = getpid(); 87dde769a2SRod Evans 88dde769a2SRod Evans /* 897c478bd9Sstevel@tonic-gate * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 907c478bd9Sstevel@tonic-gate * diagnostics to the specified file. Add the process id as a file 917c478bd9Sstevel@tonic-gate * suffix so that multiple processes that inherit the same debugging 927c478bd9Sstevel@tonic-gate * environment variable don't fight over the same file. 93e23c41c9SAli Bahrami * 94e23c41c9SAli Bahrami * If LD_DEBUG_OUTPUT is not specified, and the output=file token 95e23c41c9SAli Bahrami * was, then we direct all diagnostics to that file. Unlike 96e23c41c9SAli Bahrami * LD_DEBUG_OUTPUT, we do not add the process id suffix. This 97e23c41c9SAli Bahrami * is more convenient for interactive use. 98e23c41c9SAli Bahrami * 99e23c41c9SAli Bahrami * If neither redirection option is present, we send debugging 100e23c41c9SAli Bahrami * output to stderr. Note that the caller will not be able 101e23c41c9SAli Bahrami * to pipe or redirect this output at the shell level. libc 102e23c41c9SAli Bahrami * has not yet initialized things to make that possible. 1037c478bd9Sstevel@tonic-gate */ 104e23c41c9SAli Bahrami if (dbg_file == NULL) { 105e23c41c9SAli Bahrami if (ofile && (*ofile != '\0')) 106e23c41c9SAli Bahrami dbg_file = ofile; 107e23c41c9SAli Bahrami } else { 108e23c41c9SAli Bahrami dbg_add_pid = 1; 109e23c41c9SAli Bahrami } 1107c478bd9Sstevel@tonic-gate 111e23c41c9SAli Bahrami if (dbg_file) { 112e23c41c9SAli Bahrami char _file[MAXPATHLEN]; 113e23c41c9SAli Bahrami const char *file; 114e23c41c9SAli Bahrami 115e23c41c9SAli Bahrami if (dbg_add_pid) { 116e23c41c9SAli Bahrami file = _file; 117e23c41c9SAli Bahrami (void) snprintf(_file, MAXPATHLEN, 118e23c41c9SAli Bahrami MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 119e23c41c9SAli Bahrami } else { 120e23c41c9SAli Bahrami file = dbg_file; 121e23c41c9SAli Bahrami } 122e23c41c9SAli Bahrami dbg_fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0666); 123e23c41c9SAli Bahrami if (dbg_fd == -1) { 1247c478bd9Sstevel@tonic-gate int err = errno; 1257c478bd9Sstevel@tonic-gate 1265aefb655Srie eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 1275aefb655Srie file, strerror(err)); 1285aefb655Srie dbp->d_class = 0; 1297c478bd9Sstevel@tonic-gate return (0); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate } else { 1327c478bd9Sstevel@tonic-gate /* 1337c478bd9Sstevel@tonic-gate * The default is to direct debugging to the stderr. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate dbg_fd = 2; 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * Initialize the dev/inode pair to enable us to determine if 1407c478bd9Sstevel@tonic-gate * the debugging file descriptor is still available once the 1417c478bd9Sstevel@tonic-gate * application has been entered. 1427c478bd9Sstevel@tonic-gate */ 143cb511613SAli Bahrami (void) rtld_fstat(dbg_fd, &status); 1447c478bd9Sstevel@tonic-gate dbg_dev = status.st_dev; 1457c478bd9Sstevel@tonic-gate dbg_ino = status.st_ino; 1467c478bd9Sstevel@tonic-gate 147e23c41c9SAli Bahrami /* 148*69112eddSAli Bahrami * Now that the output file is established, identify the linker 149*69112eddSAli Bahrami * package, and generate help output if the user specified the 150*69112eddSAli Bahrami * debug help token. 151e23c41c9SAli Bahrami */ 152*69112eddSAli Bahrami Dbg_version(); 153e23c41c9SAli Bahrami if (dbp->d_extra & DBG_E_HELP) 154e23c41c9SAli Bahrami Dbg_help(); 155e23c41c9SAli Bahrami 156e23c41c9SAli Bahrami return (1); 1575aefb655Srie } 1585aefb655Srie 159e23c41c9SAli Bahrami /* 160e23c41c9SAli Bahrami * Return True (1) if dbg_print() should produce output for the 161e23c41c9SAli Bahrami * specified link-map list, and False (0) otherwise. 162e23c41c9SAli Bahrami */ 1635aefb655Srie static int 164e23c41c9SAli Bahrami dbg_lmid_validate(Lm_list *lml) 1655aefb655Srie { 166cce0e03bSab196087 const char *str; 167cce0e03bSab196087 Aliste idx; 1685aefb655Srie 169e23c41c9SAli Bahrami /* 170e23c41c9SAli Bahrami * The LDSO link-map list is a special case, requiring 171e23c41c9SAli Bahrami * an explicit user request. 172e23c41c9SAli Bahrami */ 173e23c41c9SAli Bahrami if (lml->lm_flags & LML_FLG_RTLDLM) 174e23c41c9SAli Bahrami return ((dbg_desc->d_extra & DBG_E_LMID_LDSO) != 0); 175e23c41c9SAli Bahrami 176e23c41c9SAli Bahrami /* 177e23c41c9SAli Bahrami * Approve special cases: 178e23c41c9SAli Bahrami * - The link-map list has no name 179e23c41c9SAli Bahrami * - lmid=all was set 180e23c41c9SAli Bahrami * - lmid=alt was set, and this is not the BASE linkmap 181e23c41c9SAli Bahrami */ 182e23c41c9SAli Bahrami if ((lml->lm_lmidstr == NULL) || 183e23c41c9SAli Bahrami ((dbg_desc->d_extra & DBG_E_LMID_ALL) != 0) || 184e23c41c9SAli Bahrami (((dbg_desc->d_extra & DBG_E_LMID_ALT) != 0) && 185e23c41c9SAli Bahrami ((lml->lm_flags & LML_FLG_BASELM) == 0))) 186e23c41c9SAli Bahrami return (1); 187e23c41c9SAli Bahrami 188e23c41c9SAli Bahrami /* 189e23c41c9SAli Bahrami * If there is no list of specific link-map list names to check, 190e23c41c9SAli Bahrami * then approval depends on lmid={ldso|alt} not being specified. 191e23c41c9SAli Bahrami */ 192e23c41c9SAli Bahrami if (aplist_nitems(dbg_desc->d_list) == 0) 193e23c41c9SAli Bahrami return ((dbg_desc->d_extra & 194e23c41c9SAli Bahrami (DBG_E_LMID_LDSO | DBG_E_LMID_ALT)) == 0); 195e23c41c9SAli Bahrami 196e23c41c9SAli Bahrami /* 197e23c41c9SAli Bahrami * Compare the link-map list name against the list of approved names 198e23c41c9SAli Bahrami */ 199e23c41c9SAli Bahrami for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) 200cce0e03bSab196087 if (strcmp(lml->lm_lmidstr, str) == 0) 2015aefb655Srie return (1); 202e23c41c9SAli Bahrami 203e23c41c9SAli Bahrami /* Output for this linkmap is denied */ 2045aefb655Srie return (0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * All diagnostic requests are funneled to this routine. 2097c478bd9Sstevel@tonic-gate */ 2105aefb655Srie /* PRINTFLIKE2 */ 2117c478bd9Sstevel@tonic-gate void 2125aefb655Srie dbg_print(Lm_list *lml, const char *format, ...) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate va_list args; 2157c478bd9Sstevel@tonic-gate char buffer[ERRSIZE + 1]; 2167c478bd9Sstevel@tonic-gate pid_t _pid; 217cb511613SAli Bahrami rtld_stat_t status; 2187c478bd9Sstevel@tonic-gate Prfbuf prf; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* 2215aefb655Srie * Knock off any newline indicator to signify that a diagnostic has 2225aefb655Srie * been processed. 2235aefb655Srie */ 2245aefb655Srie dbg_desc->d_extra &= ~DBG_E_STDNL; 2255aefb655Srie 2265aefb655Srie /* 2275aefb655Srie * If debugging has been isolated to individual link-map lists, 2285aefb655Srie * determine whether this request originates from a link-map list that 229e23c41c9SAli Bahrami * is being monitored. 2305aefb655Srie */ 231e23c41c9SAli Bahrami if (lml && (dbg_lmid_validate(lml) == 0)) 2325aefb655Srie return; 2335aefb655Srie 2345aefb655Srie /* 2357c478bd9Sstevel@tonic-gate * If we're in the application make sure the debugging file descriptor 2367c478bd9Sstevel@tonic-gate * is still available (ie, the user hasn't closed and/or reused the 2377c478bd9Sstevel@tonic-gate * same descriptor). 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) { 240cb511613SAli Bahrami if ((rtld_fstat(dbg_fd, &status) == -1) || 2417c478bd9Sstevel@tonic-gate (status.st_dev != dbg_dev) || 2427c478bd9Sstevel@tonic-gate (status.st_ino != dbg_ino)) { 2437c478bd9Sstevel@tonic-gate if (dbg_file) { 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * If the user specified output file has been 2467c478bd9Sstevel@tonic-gate * disconnected try and reconnect to it. 2477c478bd9Sstevel@tonic-gate */ 248e23c41c9SAli Bahrami char _file[MAXPATHLEN]; 249e23c41c9SAli Bahrami const char *file; 2507c478bd9Sstevel@tonic-gate 251e23c41c9SAli Bahrami if (dbg_add_pid) { 252e23c41c9SAli Bahrami file = _file; 253e23c41c9SAli Bahrami (void) snprintf(_file, MAXPATHLEN, 254e23c41c9SAli Bahrami MSG_ORIG(MSG_DBG_FILE), dbg_file, 255e23c41c9SAli Bahrami pid); 256e23c41c9SAli Bahrami } else { 257e23c41c9SAli Bahrami file = dbg_file; 258e23c41c9SAli Bahrami } 2597c478bd9Sstevel@tonic-gate if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 2607c478bd9Sstevel@tonic-gate 0)) == -1) { 2615aefb655Srie dbg_desc->d_class = 0; 2627c478bd9Sstevel@tonic-gate return; 2637c478bd9Sstevel@tonic-gate } 264cb511613SAli Bahrami (void) rtld_fstat(dbg_fd, &status); 2657c478bd9Sstevel@tonic-gate dbg_dev = status.st_dev; 2667c478bd9Sstevel@tonic-gate dbg_ino = status.st_ino; 2677c478bd9Sstevel@tonic-gate } else { 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * If stderr has been stolen from us simply 2707c478bd9Sstevel@tonic-gate * turn debugging off. 2717c478bd9Sstevel@tonic-gate */ 2725aefb655Srie dbg_desc->d_class = 0; 2737c478bd9Sstevel@tonic-gate return; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2785aefb655Srie prf.pr_fd = dbg_fd; 2795aefb655Srie 2807c478bd9Sstevel@tonic-gate /* 281dde769a2SRod Evans * Obtain the process id. 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate _pid = getpid(); 2847c478bd9Sstevel@tonic-gate 2852017c965SRod Evans /* 2862017c965SRod Evans * Each time ld.so.1 is entered, the diagnostic times are reset. It is 2872017c965SRod Evans * useful to convey this reset as part of our diagnostics, but only if 2882017c965SRod Evans * other diagnostics will follow. If a reset has preceded this 2892017c965SRod Evans * diagnostic, print a division line. 2902017c965SRod Evans */ 2912017c965SRod Evans if (DBG_ISRESET()) { 2922017c965SRod Evans DBG_OFFRESET(); 2932017c965SRod Evans 2942017c965SRod Evans prf.pr_buf = prf.pr_cur = buffer; 2952017c965SRod Evans prf.pr_len = ERRSIZE; 2962017c965SRod Evans 2972017c965SRod Evans if (lml) 2982017c965SRod Evans (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 2992017c965SRod Evans else 3002017c965SRod Evans (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 3012017c965SRod Evans prf.pr_cur--; 3022017c965SRod Evans 3032017c965SRod Evans (void) bufprint(&prf, MSG_ORIG(MSG_DBG_RESET)); 3042017c965SRod Evans (void) dowrite(&prf); 3052017c965SRod Evans } 3062017c965SRod Evans 3072017c965SRod Evans /* 3082017c965SRod Evans * Reestablish the buffer for standard printing. 3092017c965SRod Evans */ 3102017c965SRod Evans prf.pr_buf = prf.pr_cur = buffer; 3112017c965SRod Evans prf.pr_len = ERRSIZE; 3122017c965SRod Evans 3132017c965SRod Evans /* 3142017c965SRod Evans * Establish any diagnostic prefix strings. 3152017c965SRod Evans */ 3165aefb655Srie if (lml) 3175aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 3187c478bd9Sstevel@tonic-gate else 3195aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 3205aefb655Srie prf.pr_cur--; 3215aefb655Srie 3225aefb655Srie if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 3235aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 3245aefb655Srie prf.pr_cur--; 3255aefb655Srie } 3262017c965SRod Evans if (DBG_ISTIME()) { 3272017c965SRod Evans struct timeval new; 3282017c965SRod Evans 3292017c965SRod Evans if (gettimeofday(&new, NULL) == 0) { 3302017c965SRod Evans Conv_time_buf_t buf; 3312017c965SRod Evans 3322017c965SRod Evans if (DBG_ISTTIME()) { 3332017c965SRod Evans (void) bufprint(&prf, 3342017c965SRod Evans conv_time(&DBG_TOTALTIME, &new, &buf)); 3352017c965SRod Evans prf.pr_cur--; 3362017c965SRod Evans } 3372017c965SRod Evans if (DBG_ISDTIME()) { 3382017c965SRod Evans (void) bufprint(&prf, 3392017c965SRod Evans conv_time(&DBG_DELTATIME, &new, &buf)); 3402017c965SRod Evans prf.pr_cur--; 3412017c965SRod Evans } 3422017c965SRod Evans DBG_DELTATIME = new; 3432017c965SRod Evans } 3442017c965SRod Evans } 3455aefb655Srie if (rtld_flags & RT_FL_THREADS) { 3465aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 3475aefb655Srie prf.pr_cur--; 3485aefb655Srie } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* 3517c478bd9Sstevel@tonic-gate * Format the message and print it. 3527c478bd9Sstevel@tonic-gate */ 3537c478bd9Sstevel@tonic-gate va_start(args, format); 3547c478bd9Sstevel@tonic-gate (void) doprf(format, args, &prf); 3557c478bd9Sstevel@tonic-gate *(prf.pr_cur - 1) = '\n'; 3567c478bd9Sstevel@tonic-gate (void) dowrite(&prf); 3577c478bd9Sstevel@tonic-gate va_end(args); 3587c478bd9Sstevel@tonic-gate } 359