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 /* 23*5892Sab196087 * Copyright 2008 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> 411618Srie #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 */ 561618Srie uintptr_t 571618Srie dbg_setup(const char *options, Dbg_desc *dbp) 580Sstevel@tonic-gate { 591618Srie 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 */ 901618Srie if ((ret = Dbg_setup(options, dbp)) != (uintptr_t)1) 911618Srie 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 1021618Srie (void) snprintf(file, MAXPATHLEN, MSG_ORIG(MSG_DBG_FILE), 1031618Srie 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 1071618Srie eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 1081618Srie file, strerror(err)); 1091618Srie 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 1291618Srie return (ret); 1301618Srie } 1311618Srie 1321618Srie static int 1331618Srie dbg_lmid(Lm_list *lml) 1341618Srie { 135*5892Sab196087 const char *str; 136*5892Sab196087 Aliste idx; 1371618Srie 138*5892Sab196087 for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) { 139*5892Sab196087 if (strcmp(lml->lm_lmidstr, str) == 0) 1401618Srie return (1); 1411618Srie } 1421618Srie 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 */ 1481618Srie /* PRINTFLIKE2 */ 1490Sstevel@tonic-gate void 1501618Srie dbg_print(Lm_list *lml, const char *format, ...) 1510Sstevel@tonic-gate { 1521618Srie va_list args; 1531618Srie char buffer[ERRSIZE + 1]; 1541618Srie pid_t _pid; 1551618Srie struct stat status; 1561618Srie Prfbuf prf; 1571618Srie 1581618Srie /* 1591618Srie * Knock off any newline indicator to signify that a diagnostic has 1601618Srie * been processed. 1611618Srie */ 1621618Srie dbg_desc->d_extra &= ~DBG_E_STDNL; 1631618Srie 1641618Srie /* 1651618Srie * If debugging has been isolated to individual link-map lists, 1661618Srie * determine whether this request originates from a link-map list that 1671618Srie * is being monitored. Otherwise, process all link-map list diagnostics 1681618Srie * except those that originate from ld.so.1 processing its own 1691618Srie * dependencies. 1701618Srie */ 1711618Srie if (dbg_desc->d_list && lml && lml->lm_lmidstr) { 1721618Srie if (dbg_lmid(lml) == 0) 1731618Srie return; 1741618Srie } else if (lml && (lml->lm_flags & LML_FLG_RTLDLM)) 1751618Srie 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, 1941618Srie 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) { 1971618Srie 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 */ 2081618Srie dbg_desc->d_class = 0; 2090Sstevel@tonic-gate return; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate 2141618Srie prf.pr_buf = prf.pr_cur = buffer; 2151618Srie prf.pr_len = ERRSIZE; 2161618Srie prf.pr_fd = dbg_fd; 2171618Srie 2180Sstevel@tonic-gate /* 2191618Srie * The getpid() call is a 'special' interface between ld.so.1 and dbx, 2201618Srie * because of this getpid() can't be called freely until after control 2211618Srie * has been given to the user program. Once the control has been given 2221618Srie * to the user program we know that the r_debug structure has been 2231618Srie * 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 2301618Srie if (lml) 2311618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 2321618Srie else 2331618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 2341618Srie prf.pr_cur--; 2350Sstevel@tonic-gate 2361618Srie if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 2371618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 2381618Srie prf.pr_cur--; 2391618Srie } 2401618Srie if (rtld_flags & RT_FL_THREADS) { 2411618Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 2421618Srie prf.pr_cur--; 2431618Srie } 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