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 5*1618Srie * Common Development and Distribution License (the "License"). 6*1618Srie * 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 */ 21*1618Srie 220Sstevel@tonic-gate /* 23*1618Srie * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include "_synonyms.h" 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <sys/types.h> 320Sstevel@tonic-gate #include <sys/stat.h> 330Sstevel@tonic-gate #include <sys/param.h> 340Sstevel@tonic-gate #include <stdio.h> 350Sstevel@tonic-gate #include <fcntl.h> 360Sstevel@tonic-gate #include <stdarg.h> 370Sstevel@tonic-gate #include <dlfcn.h> 380Sstevel@tonic-gate #include <unistd.h> 390Sstevel@tonic-gate #include <string.h> 400Sstevel@tonic-gate #include <thread.h> 41*1618Srie #include <debug.h> 420Sstevel@tonic-gate #include "_rtld.h" 430Sstevel@tonic-gate #include "_elf.h" 440Sstevel@tonic-gate #include "msg.h" 450Sstevel@tonic-gate 460Sstevel@tonic-gate 470Sstevel@tonic-gate static int dbg_fd; /* debugging output file descriptor */ 480Sstevel@tonic-gate static dev_t dbg_dev; 490Sstevel@tonic-gate static ino_t dbg_ino; 500Sstevel@tonic-gate static pid_t pid; 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * Enable diagnostic output. All debugging functions reside in the linker 540Sstevel@tonic-gate * debugging library liblddbg.so which is lazy loaded when required. 550Sstevel@tonic-gate */ 56*1618Srie uintptr_t 57*1618Srie dbg_setup(const char *options, Dbg_desc *dbp) 580Sstevel@tonic-gate { 59*1618Srie uintptr_t ret; 600Sstevel@tonic-gate struct stat status; 610Sstevel@tonic-gate 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * If we're running secure, only allow debugging if ld.so.1 itself is 640Sstevel@tonic-gate * owned by root and has its mode setuid. Fail silently. 650Sstevel@tonic-gate */ 660Sstevel@tonic-gate if (rtld_flags & RT_FL_SECURE) { 670Sstevel@tonic-gate struct stat status; 680Sstevel@tonic-gate 690Sstevel@tonic-gate if (stat(NAME(lml_rtld.lm_head), &status) == 0) { 700Sstevel@tonic-gate if ((status.st_uid != 0) || 710Sstevel@tonic-gate (!(status.st_mode & S_ISUID))) 720Sstevel@tonic-gate return (0); 730Sstevel@tonic-gate } else 740Sstevel@tonic-gate return (0); 750Sstevel@tonic-gate } 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* 780Sstevel@tonic-gate * As Dbg_setup() will effectively lazy load the necessary support 790Sstevel@tonic-gate * libraries, make sure ld.so.1 is initialized for plt relocations. 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate if (elf_rtld_load() == 0) 820Sstevel@tonic-gate return (0); 830Sstevel@tonic-gate 840Sstevel@tonic-gate /* 850Sstevel@tonic-gate * Call the debugging setup routine. This function verifies the 860Sstevel@tonic-gate * debugging tokens provided and returns a mask indicating the debugging 870Sstevel@tonic-gate * categories selected. The mask effectively enables calls to the 880Sstevel@tonic-gate * debugging library. 890Sstevel@tonic-gate */ 90*1618Srie if ((ret = Dbg_setup(options, dbp)) != (uintptr_t)1) 91*1618Srie return (ret); 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 950Sstevel@tonic-gate * diagnostics to the specified file. Add the process id as a file 960Sstevel@tonic-gate * suffix so that multiple processes that inherit the same debugging 970Sstevel@tonic-gate * environment variable don't fight over the same file. 980Sstevel@tonic-gate */ 990Sstevel@tonic-gate if (dbg_file) { 1000Sstevel@tonic-gate char file[MAXPATHLEN]; 1010Sstevel@tonic-gate 102*1618Srie (void) snprintf(file, MAXPATHLEN, MSG_ORIG(MSG_DBG_FILE), 103*1618Srie dbg_file, getpid()); 1040Sstevel@tonic-gate if ((dbg_fd = open(file, (O_RDWR | O_CREAT), 0666)) == -1) { 1050Sstevel@tonic-gate int err = errno; 1060Sstevel@tonic-gate 107*1618Srie eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 108*1618Srie file, strerror(err)); 109*1618Srie dbp->d_class = 0; 1100Sstevel@tonic-gate return (0); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate } else { 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * The default is to direct debugging to the stderr. 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate dbg_fd = 2; 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Initialize the dev/inode pair to enable us to determine if 1210Sstevel@tonic-gate * the debugging file descriptor is still available once the 1220Sstevel@tonic-gate * application has been entered. 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate (void) fstat(dbg_fd, &status); 1250Sstevel@tonic-gate dbg_dev = status.st_dev; 1260Sstevel@tonic-gate dbg_ino = status.st_ino; 1270Sstevel@tonic-gate pid = getpid(); 1280Sstevel@tonic-gate 129*1618Srie return (ret); 130*1618Srie } 131*1618Srie 132*1618Srie static int 133*1618Srie dbg_lmid(Lm_list *lml) 134*1618Srie { 135*1618Srie const char **str; 136*1618Srie Aliste off; 137*1618Srie 138*1618Srie for (ALIST_TRAVERSE(dbg_desc->d_list, off, str)) { 139*1618Srie if (strcmp(lml->lm_lmidstr, *str) == 0) 140*1618Srie return (1); 141*1618Srie } 142*1618Srie return (0); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * All diagnostic requests are funneled to this routine. 1470Sstevel@tonic-gate */ 148*1618Srie /* PRINTFLIKE2 */ 1490Sstevel@tonic-gate void 150*1618Srie dbg_print(Lm_list *lml, const char *format, ...) 1510Sstevel@tonic-gate { 152*1618Srie va_list args; 153*1618Srie char buffer[ERRSIZE + 1]; 154*1618Srie pid_t _pid; 155*1618Srie struct stat status; 156*1618Srie Prfbuf prf; 157*1618Srie 158*1618Srie /* 159*1618Srie * Knock off any newline indicator to signify that a diagnostic has 160*1618Srie * been processed. 161*1618Srie */ 162*1618Srie dbg_desc->d_extra &= ~DBG_E_STDNL; 163*1618Srie 164*1618Srie /* 165*1618Srie * If debugging has been isolated to individual link-map lists, 166*1618Srie * determine whether this request originates from a link-map list that 167*1618Srie * is being monitored. Otherwise, process all link-map list diagnostics 168*1618Srie * except those that originate from ld.so.1 processing its own 169*1618Srie * dependencies. 170*1618Srie */ 171*1618Srie if (dbg_desc->d_list && lml && lml->lm_lmidstr) { 172*1618Srie if (dbg_lmid(lml) == 0) 173*1618Srie return; 174*1618Srie } else if (lml && (lml->lm_flags & LML_FLG_RTLDLM)) 175*1618Srie return; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate /* 1780Sstevel@tonic-gate * If we're in the application make sure the debugging file descriptor 1790Sstevel@tonic-gate * is still available (ie, the user hasn't closed and/or reused the 1800Sstevel@tonic-gate * same descriptor). 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) { 1830Sstevel@tonic-gate if ((fstat(dbg_fd, &status) == -1) || 1840Sstevel@tonic-gate (status.st_dev != dbg_dev) || 1850Sstevel@tonic-gate (status.st_ino != dbg_ino)) { 1860Sstevel@tonic-gate if (dbg_file) { 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * If the user specified output file has been 1890Sstevel@tonic-gate * disconnected try and reconnect to it. 1900Sstevel@tonic-gate */ 1910Sstevel@tonic-gate char file[MAXPATHLEN]; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate (void) snprintf(file, MAXPATHLEN, 194*1618Srie MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 1950Sstevel@tonic-gate if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 1960Sstevel@tonic-gate 0)) == -1) { 197*1618Srie dbg_desc->d_class = 0; 1980Sstevel@tonic-gate return; 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate (void) fstat(dbg_fd, &status); 2010Sstevel@tonic-gate dbg_dev = status.st_dev; 2020Sstevel@tonic-gate dbg_ino = status.st_ino; 2030Sstevel@tonic-gate } else { 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * If stderr has been stolen from us simply 2060Sstevel@tonic-gate * turn debugging off. 2070Sstevel@tonic-gate */ 208*1618Srie dbg_desc->d_class = 0; 2090Sstevel@tonic-gate return; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate 214*1618Srie prf.pr_buf = prf.pr_cur = buffer; 215*1618Srie prf.pr_len = ERRSIZE; 216*1618Srie prf.pr_fd = dbg_fd; 217*1618Srie 2180Sstevel@tonic-gate /* 219*1618Srie * The getpid() call is a 'special' interface between ld.so.1 and dbx, 220*1618Srie * because of this getpid() can't be called freely until after control 221*1618Srie * has been given to the user program. Once the control has been given 222*1618Srie * to the user program we know that the r_debug structure has been 223*1618Srie * properly initialized for the debugger. 2240Sstevel@tonic-gate */ 2250Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) 2260Sstevel@tonic-gate _pid = getpid(); 2270Sstevel@tonic-gate else 2280Sstevel@tonic-gate _pid = pid; 2290Sstevel@tonic-gate 230*1618Srie if (lml) 231*1618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 232*1618Srie else 233*1618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 234*1618Srie prf.pr_cur--; 2350Sstevel@tonic-gate 236*1618Srie if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 237*1618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 238*1618Srie prf.pr_cur--; 239*1618Srie } 240*1618Srie if (rtld_flags & RT_FL_THREADS) { 241*1618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 242*1618Srie prf.pr_cur--; 243*1618Srie } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* 2460Sstevel@tonic-gate * Format the message and print it. 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate va_start(args, format); 2490Sstevel@tonic-gate (void) doprf(format, args, &prf); 2500Sstevel@tonic-gate *(prf.pr_cur - 1) = '\n'; 2510Sstevel@tonic-gate (void) dowrite(&prf); 2520Sstevel@tonic-gate va_end(args); 2530Sstevel@tonic-gate } 254