10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211618Srie 220Sstevel@tonic-gate /* 239340SRod.Evans@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/types.h> 280Sstevel@tonic-gate #include <sys/stat.h> 290Sstevel@tonic-gate #include <sys/param.h> 300Sstevel@tonic-gate #include <stdio.h> 310Sstevel@tonic-gate #include <fcntl.h> 320Sstevel@tonic-gate #include <stdarg.h> 330Sstevel@tonic-gate #include <dlfcn.h> 340Sstevel@tonic-gate #include <unistd.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <thread.h> 371618Srie #include <debug.h> 380Sstevel@tonic-gate #include "_rtld.h" 390Sstevel@tonic-gate #include "_elf.h" 400Sstevel@tonic-gate #include "msg.h" 410Sstevel@tonic-gate 420Sstevel@tonic-gate 438394SAli.Bahrami@Sun.COM static int dbg_fd; /* debugging output file descriptor */ 448394SAli.Bahrami@Sun.COM static dev_t dbg_dev; 458394SAli.Bahrami@Sun.COM static rtld_ino_t dbg_ino; 46*9406SAli.Bahrami@Sun.COM static int dbg_add_pid; /* True to add pid to debug file name */ 478394SAli.Bahrami@Sun.COM static pid_t pid; 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * Enable diagnostic output. All debugging functions reside in the linker 510Sstevel@tonic-gate * debugging library liblddbg.so which is lazy loaded when required. 520Sstevel@tonic-gate */ 53*9406SAli.Bahrami@Sun.COM int 541618Srie dbg_setup(const char *options, Dbg_desc *dbp) 550Sstevel@tonic-gate { 568394SAli.Bahrami@Sun.COM rtld_stat_t status; 57*9406SAli.Bahrami@Sun.COM const char *ofile; 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * If we're running secure, only allow debugging if ld.so.1 itself is 610Sstevel@tonic-gate * owned by root and has its mode setuid. Fail silently. 620Sstevel@tonic-gate */ 637668SRod.Evans@Sun.COM if ((rtld_flags & RT_FL_SECURE) && (is_rtld_setuid() == 0)) 64*9406SAli.Bahrami@Sun.COM return (1); 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * As Dbg_setup() will effectively lazy load the necessary support 680Sstevel@tonic-gate * libraries, make sure ld.so.1 is initialized for plt relocations. 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate if (elf_rtld_load() == 0) 71*9406SAli.Bahrami@Sun.COM return (1); 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * Call the debugging setup routine. This function verifies the 750Sstevel@tonic-gate * debugging tokens provided and returns a mask indicating the debugging 760Sstevel@tonic-gate * categories selected. The mask effectively enables calls to the 770Sstevel@tonic-gate * debugging library. 780Sstevel@tonic-gate */ 79*9406SAli.Bahrami@Sun.COM if (Dbg_setup(DBG_CALLER_RTLD, options, dbp, &ofile) == 0) 80*9406SAli.Bahrami@Sun.COM return (0); 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 839340SRod.Evans@Sun.COM * Obtain the process id. 849340SRod.Evans@Sun.COM */ 859340SRod.Evans@Sun.COM pid = getpid(); 869340SRod.Evans@Sun.COM 879340SRod.Evans@Sun.COM /* 880Sstevel@tonic-gate * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 890Sstevel@tonic-gate * diagnostics to the specified file. Add the process id as a file 900Sstevel@tonic-gate * suffix so that multiple processes that inherit the same debugging 910Sstevel@tonic-gate * environment variable don't fight over the same file. 92*9406SAli.Bahrami@Sun.COM * 93*9406SAli.Bahrami@Sun.COM * If LD_DEBUG_OUTPUT is not specified, and the output=file token 94*9406SAli.Bahrami@Sun.COM * was, then we direct all diagnostics to that file. Unlike 95*9406SAli.Bahrami@Sun.COM * LD_DEBUG_OUTPUT, we do not add the process id suffix. This 96*9406SAli.Bahrami@Sun.COM * is more convenient for interactive use. 97*9406SAli.Bahrami@Sun.COM * 98*9406SAli.Bahrami@Sun.COM * If neither redirection option is present, we send debugging 99*9406SAli.Bahrami@Sun.COM * output to stderr. Note that the caller will not be able 100*9406SAli.Bahrami@Sun.COM * to pipe or redirect this output at the shell level. libc 101*9406SAli.Bahrami@Sun.COM * has not yet initialized things to make that possible. 1020Sstevel@tonic-gate */ 103*9406SAli.Bahrami@Sun.COM if (dbg_file == NULL) { 104*9406SAli.Bahrami@Sun.COM if (ofile && (*ofile != '\0')) 105*9406SAli.Bahrami@Sun.COM dbg_file = ofile; 106*9406SAli.Bahrami@Sun.COM } else { 107*9406SAli.Bahrami@Sun.COM dbg_add_pid = 1; 108*9406SAli.Bahrami@Sun.COM } 1090Sstevel@tonic-gate 110*9406SAli.Bahrami@Sun.COM if (dbg_file) { 111*9406SAli.Bahrami@Sun.COM char _file[MAXPATHLEN]; 112*9406SAli.Bahrami@Sun.COM const char *file; 113*9406SAli.Bahrami@Sun.COM 114*9406SAli.Bahrami@Sun.COM if (dbg_add_pid) { 115*9406SAli.Bahrami@Sun.COM file = _file; 116*9406SAli.Bahrami@Sun.COM (void) snprintf(_file, MAXPATHLEN, 117*9406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 118*9406SAli.Bahrami@Sun.COM } else { 119*9406SAli.Bahrami@Sun.COM file = dbg_file; 120*9406SAli.Bahrami@Sun.COM } 121*9406SAli.Bahrami@Sun.COM dbg_fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0666); 122*9406SAli.Bahrami@Sun.COM if (dbg_fd == -1) { 1230Sstevel@tonic-gate int err = errno; 1240Sstevel@tonic-gate 1251618Srie eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 1261618Srie file, strerror(err)); 1271618Srie dbp->d_class = 0; 1280Sstevel@tonic-gate return (0); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate } else { 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * The default is to direct debugging to the stderr. 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate dbg_fd = 2; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Initialize the dev/inode pair to enable us to determine if 1390Sstevel@tonic-gate * the debugging file descriptor is still available once the 1400Sstevel@tonic-gate * application has been entered. 1410Sstevel@tonic-gate */ 1428394SAli.Bahrami@Sun.COM (void) rtld_fstat(dbg_fd, &status); 1430Sstevel@tonic-gate dbg_dev = status.st_dev; 1440Sstevel@tonic-gate dbg_ino = status.st_ino; 1450Sstevel@tonic-gate 146*9406SAli.Bahrami@Sun.COM /* 147*9406SAli.Bahrami@Sun.COM * Now that the output file is established, generate help 148*9406SAli.Bahrami@Sun.COM * output if the user specified the debug help token. 149*9406SAli.Bahrami@Sun.COM */ 150*9406SAli.Bahrami@Sun.COM if (dbp->d_extra & DBG_E_HELP) 151*9406SAli.Bahrami@Sun.COM Dbg_help(); 152*9406SAli.Bahrami@Sun.COM 153*9406SAli.Bahrami@Sun.COM return (1); 1541618Srie } 1551618Srie 156*9406SAli.Bahrami@Sun.COM /* 157*9406SAli.Bahrami@Sun.COM * Return True (1) if dbg_print() should produce output for the 158*9406SAli.Bahrami@Sun.COM * specified link-map list, and False (0) otherwise. 159*9406SAli.Bahrami@Sun.COM */ 1601618Srie static int 161*9406SAli.Bahrami@Sun.COM dbg_lmid_validate(Lm_list *lml) 1621618Srie { 1635892Sab196087 const char *str; 1645892Sab196087 Aliste idx; 1651618Srie 166*9406SAli.Bahrami@Sun.COM /* 167*9406SAli.Bahrami@Sun.COM * The LDSO link-map list is a special case, requiring 168*9406SAli.Bahrami@Sun.COM * an explicit user request. 169*9406SAli.Bahrami@Sun.COM */ 170*9406SAli.Bahrami@Sun.COM if (lml->lm_flags & LML_FLG_RTLDLM) 171*9406SAli.Bahrami@Sun.COM return ((dbg_desc->d_extra & DBG_E_LMID_LDSO) != 0); 172*9406SAli.Bahrami@Sun.COM 173*9406SAli.Bahrami@Sun.COM /* 174*9406SAli.Bahrami@Sun.COM * Approve special cases: 175*9406SAli.Bahrami@Sun.COM * - The link-map list has no name 176*9406SAli.Bahrami@Sun.COM * - lmid=all was set 177*9406SAli.Bahrami@Sun.COM * - lmid=alt was set, and this is not the BASE linkmap 178*9406SAli.Bahrami@Sun.COM */ 179*9406SAli.Bahrami@Sun.COM if ((lml->lm_lmidstr == NULL) || 180*9406SAli.Bahrami@Sun.COM ((dbg_desc->d_extra & DBG_E_LMID_ALL) != 0) || 181*9406SAli.Bahrami@Sun.COM (((dbg_desc->d_extra & DBG_E_LMID_ALT) != 0) && 182*9406SAli.Bahrami@Sun.COM ((lml->lm_flags & LML_FLG_BASELM) == 0))) 183*9406SAli.Bahrami@Sun.COM return (1); 184*9406SAli.Bahrami@Sun.COM 185*9406SAli.Bahrami@Sun.COM /* 186*9406SAli.Bahrami@Sun.COM * If there is no list of specific link-map list names to check, 187*9406SAli.Bahrami@Sun.COM * then approval depends on lmid={ldso|alt} not being specified. 188*9406SAli.Bahrami@Sun.COM */ 189*9406SAli.Bahrami@Sun.COM if (aplist_nitems(dbg_desc->d_list) == 0) 190*9406SAli.Bahrami@Sun.COM return ((dbg_desc->d_extra & 191*9406SAli.Bahrami@Sun.COM (DBG_E_LMID_LDSO | DBG_E_LMID_ALT)) == 0); 192*9406SAli.Bahrami@Sun.COM 193*9406SAli.Bahrami@Sun.COM /* 194*9406SAli.Bahrami@Sun.COM * Compare the link-map list name against the list of approved names 195*9406SAli.Bahrami@Sun.COM */ 196*9406SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) 1975892Sab196087 if (strcmp(lml->lm_lmidstr, str) == 0) 1981618Srie return (1); 199*9406SAli.Bahrami@Sun.COM 200*9406SAli.Bahrami@Sun.COM /* Output for this linkmap is denied */ 2011618Srie return (0); 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * All diagnostic requests are funneled to this routine. 2060Sstevel@tonic-gate */ 2071618Srie /* PRINTFLIKE2 */ 2080Sstevel@tonic-gate void 2091618Srie dbg_print(Lm_list *lml, const char *format, ...) 2100Sstevel@tonic-gate { 2111618Srie va_list args; 2121618Srie char buffer[ERRSIZE + 1]; 2131618Srie pid_t _pid; 2148394SAli.Bahrami@Sun.COM rtld_stat_t status; 2151618Srie Prfbuf prf; 2161618Srie 2171618Srie /* 2181618Srie * Knock off any newline indicator to signify that a diagnostic has 2191618Srie * been processed. 2201618Srie */ 2211618Srie dbg_desc->d_extra &= ~DBG_E_STDNL; 2221618Srie 2231618Srie /* 2241618Srie * If debugging has been isolated to individual link-map lists, 2251618Srie * determine whether this request originates from a link-map list that 226*9406SAli.Bahrami@Sun.COM * is being monitored. 2271618Srie */ 228*9406SAli.Bahrami@Sun.COM if (lml && (dbg_lmid_validate(lml) == 0)) 2291618Srie return; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * If we're in the application make sure the debugging file descriptor 2330Sstevel@tonic-gate * is still available (ie, the user hasn't closed and/or reused the 2340Sstevel@tonic-gate * same descriptor). 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) { 2378394SAli.Bahrami@Sun.COM if ((rtld_fstat(dbg_fd, &status) == -1) || 2380Sstevel@tonic-gate (status.st_dev != dbg_dev) || 2390Sstevel@tonic-gate (status.st_ino != dbg_ino)) { 2400Sstevel@tonic-gate if (dbg_file) { 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * If the user specified output file has been 2430Sstevel@tonic-gate * disconnected try and reconnect to it. 2440Sstevel@tonic-gate */ 245*9406SAli.Bahrami@Sun.COM char _file[MAXPATHLEN]; 246*9406SAli.Bahrami@Sun.COM const char *file; 2470Sstevel@tonic-gate 248*9406SAli.Bahrami@Sun.COM if (dbg_add_pid) { 249*9406SAli.Bahrami@Sun.COM file = _file; 250*9406SAli.Bahrami@Sun.COM (void) snprintf(_file, MAXPATHLEN, 251*9406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_DBG_FILE), dbg_file, 252*9406SAli.Bahrami@Sun.COM pid); 253*9406SAli.Bahrami@Sun.COM } else { 254*9406SAli.Bahrami@Sun.COM file = dbg_file; 255*9406SAli.Bahrami@Sun.COM } 2560Sstevel@tonic-gate if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 2570Sstevel@tonic-gate 0)) == -1) { 2581618Srie dbg_desc->d_class = 0; 2590Sstevel@tonic-gate return; 2600Sstevel@tonic-gate } 2618394SAli.Bahrami@Sun.COM (void) rtld_fstat(dbg_fd, &status); 2620Sstevel@tonic-gate dbg_dev = status.st_dev; 2630Sstevel@tonic-gate dbg_ino = status.st_ino; 2640Sstevel@tonic-gate } else { 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * If stderr has been stolen from us simply 2670Sstevel@tonic-gate * turn debugging off. 2680Sstevel@tonic-gate */ 2691618Srie dbg_desc->d_class = 0; 2700Sstevel@tonic-gate return; 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2751618Srie prf.pr_buf = prf.pr_cur = buffer; 2761618Srie prf.pr_len = ERRSIZE; 2771618Srie prf.pr_fd = dbg_fd; 2781618Srie 2790Sstevel@tonic-gate /* 2809340SRod.Evans@Sun.COM * Obtain the process id. 2810Sstevel@tonic-gate */ 2829340SRod.Evans@Sun.COM _pid = getpid(); 2830Sstevel@tonic-gate 2841618Srie if (lml) 2851618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 2861618Srie else 2871618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 2881618Srie prf.pr_cur--; 2890Sstevel@tonic-gate 2901618Srie if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 2911618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 2921618Srie prf.pr_cur--; 2931618Srie } 2941618Srie if (rtld_flags & RT_FL_THREADS) { 2951618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 2961618Srie prf.pr_cur--; 2971618Srie } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate /* 3000Sstevel@tonic-gate * Format the message and print it. 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate va_start(args, format); 3030Sstevel@tonic-gate (void) doprf(format, args, &prf); 3040Sstevel@tonic-gate *(prf.pr_cur - 1) = '\n'; 3050Sstevel@tonic-gate (void) dowrite(&prf); 3060Sstevel@tonic-gate va_end(args); 3070Sstevel@tonic-gate } 308