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 /* 23cce0e03bSab * Copyright 2008 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> 387c478bd9Sstevel@tonic-gate #include "_rtld.h" 397c478bd9Sstevel@tonic-gate #include "_elf.h" 407c478bd9Sstevel@tonic-gate #include "msg.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate 43*cb511613SAli Bahrami static int dbg_fd; /* debugging output file descriptor */ 44*cb511613SAli Bahrami static dev_t dbg_dev; 45*cb511613SAli Bahrami static rtld_ino_t dbg_ino; 46*cb511613SAli Bahrami static pid_t pid; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * Enable diagnostic output. All debugging functions reside in the linker 507c478bd9Sstevel@tonic-gate * debugging library liblddbg.so which is lazy loaded when required. 517c478bd9Sstevel@tonic-gate */ 525aefb655Srie uintptr_t 535aefb655Srie dbg_setup(const char *options, Dbg_desc *dbp) 547c478bd9Sstevel@tonic-gate { 555aefb655Srie uintptr_t ret; 56*cb511613SAli Bahrami rtld_stat_t status; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * If we're running secure, only allow debugging if ld.so.1 itself is 607c478bd9Sstevel@tonic-gate * owned by root and has its mode setuid. Fail silently. 617c478bd9Sstevel@tonic-gate */ 623dbfc803SRod Evans if ((rtld_flags & RT_FL_SECURE) && (is_rtld_setuid() == 0)) 633dbfc803SRod Evans return (0); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * As Dbg_setup() will effectively lazy load the necessary support 677c478bd9Sstevel@tonic-gate * libraries, make sure ld.so.1 is initialized for plt relocations. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate if (elf_rtld_load() == 0) 707c478bd9Sstevel@tonic-gate return (0); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Call the debugging setup routine. This function verifies the 747c478bd9Sstevel@tonic-gate * debugging tokens provided and returns a mask indicating the debugging 757c478bd9Sstevel@tonic-gate * categories selected. The mask effectively enables calls to the 767c478bd9Sstevel@tonic-gate * debugging library. 777c478bd9Sstevel@tonic-gate */ 785aefb655Srie if ((ret = Dbg_setup(options, dbp)) != (uintptr_t)1) 795aefb655Srie return (ret); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 837c478bd9Sstevel@tonic-gate * diagnostics to the specified file. Add the process id as a file 847c478bd9Sstevel@tonic-gate * suffix so that multiple processes that inherit the same debugging 857c478bd9Sstevel@tonic-gate * environment variable don't fight over the same file. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate if (dbg_file) { 887c478bd9Sstevel@tonic-gate char file[MAXPATHLEN]; 897c478bd9Sstevel@tonic-gate 905aefb655Srie (void) snprintf(file, MAXPATHLEN, MSG_ORIG(MSG_DBG_FILE), 915aefb655Srie dbg_file, getpid()); 927c478bd9Sstevel@tonic-gate if ((dbg_fd = open(file, (O_RDWR | O_CREAT), 0666)) == -1) { 937c478bd9Sstevel@tonic-gate int err = errno; 947c478bd9Sstevel@tonic-gate 955aefb655Srie eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 965aefb655Srie file, strerror(err)); 975aefb655Srie dbp->d_class = 0; 987c478bd9Sstevel@tonic-gate return (0); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate } else { 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * The default is to direct debugging to the stderr. 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate dbg_fd = 2; 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Initialize the dev/inode pair to enable us to determine if 1097c478bd9Sstevel@tonic-gate * the debugging file descriptor is still available once the 1107c478bd9Sstevel@tonic-gate * application has been entered. 1117c478bd9Sstevel@tonic-gate */ 112*cb511613SAli Bahrami (void) rtld_fstat(dbg_fd, &status); 1137c478bd9Sstevel@tonic-gate dbg_dev = status.st_dev; 1147c478bd9Sstevel@tonic-gate dbg_ino = status.st_ino; 1157c478bd9Sstevel@tonic-gate pid = getpid(); 1167c478bd9Sstevel@tonic-gate 1175aefb655Srie return (ret); 1185aefb655Srie } 1195aefb655Srie 1205aefb655Srie static int 1215aefb655Srie dbg_lmid(Lm_list *lml) 1225aefb655Srie { 123cce0e03bSab const char *str; 124cce0e03bSab Aliste idx; 1255aefb655Srie 126cce0e03bSab for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) { 127cce0e03bSab if (strcmp(lml->lm_lmidstr, str) == 0) 1285aefb655Srie return (1); 1295aefb655Srie } 1305aefb655Srie return (0); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * All diagnostic requests are funneled to this routine. 1357c478bd9Sstevel@tonic-gate */ 1365aefb655Srie /* PRINTFLIKE2 */ 1377c478bd9Sstevel@tonic-gate void 1385aefb655Srie dbg_print(Lm_list *lml, const char *format, ...) 1397c478bd9Sstevel@tonic-gate { 1405aefb655Srie va_list args; 1415aefb655Srie char buffer[ERRSIZE + 1]; 1425aefb655Srie pid_t _pid; 143*cb511613SAli Bahrami rtld_stat_t status; 1445aefb655Srie Prfbuf prf; 1455aefb655Srie 1465aefb655Srie /* 1475aefb655Srie * Knock off any newline indicator to signify that a diagnostic has 1485aefb655Srie * been processed. 1495aefb655Srie */ 1505aefb655Srie dbg_desc->d_extra &= ~DBG_E_STDNL; 1515aefb655Srie 1525aefb655Srie /* 1535aefb655Srie * If debugging has been isolated to individual link-map lists, 1545aefb655Srie * determine whether this request originates from a link-map list that 1555aefb655Srie * is being monitored. Otherwise, process all link-map list diagnostics 1565aefb655Srie * except those that originate from ld.so.1 processing its own 1575aefb655Srie * dependencies. 1585aefb655Srie */ 1595aefb655Srie if (dbg_desc->d_list && lml && lml->lm_lmidstr) { 1605aefb655Srie if (dbg_lmid(lml) == 0) 1615aefb655Srie return; 1625aefb655Srie } else if (lml && (lml->lm_flags & LML_FLG_RTLDLM)) 1635aefb655Srie return; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1667c478bd9Sstevel@tonic-gate * If we're in the application make sure the debugging file descriptor 1677c478bd9Sstevel@tonic-gate * is still available (ie, the user hasn't closed and/or reused the 1687c478bd9Sstevel@tonic-gate * same descriptor). 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) { 171*cb511613SAli Bahrami if ((rtld_fstat(dbg_fd, &status) == -1) || 1727c478bd9Sstevel@tonic-gate (status.st_dev != dbg_dev) || 1737c478bd9Sstevel@tonic-gate (status.st_ino != dbg_ino)) { 1747c478bd9Sstevel@tonic-gate if (dbg_file) { 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * If the user specified output file has been 1777c478bd9Sstevel@tonic-gate * disconnected try and reconnect to it. 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate char file[MAXPATHLEN]; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate (void) snprintf(file, MAXPATHLEN, 1825aefb655Srie MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 1837c478bd9Sstevel@tonic-gate if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 1847c478bd9Sstevel@tonic-gate 0)) == -1) { 1855aefb655Srie dbg_desc->d_class = 0; 1867c478bd9Sstevel@tonic-gate return; 1877c478bd9Sstevel@tonic-gate } 188*cb511613SAli Bahrami (void) rtld_fstat(dbg_fd, &status); 1897c478bd9Sstevel@tonic-gate dbg_dev = status.st_dev; 1907c478bd9Sstevel@tonic-gate dbg_ino = status.st_ino; 1917c478bd9Sstevel@tonic-gate } else { 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * If stderr has been stolen from us simply 1947c478bd9Sstevel@tonic-gate * turn debugging off. 1957c478bd9Sstevel@tonic-gate */ 1965aefb655Srie dbg_desc->d_class = 0; 1977c478bd9Sstevel@tonic-gate return; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2025aefb655Srie prf.pr_buf = prf.pr_cur = buffer; 2035aefb655Srie prf.pr_len = ERRSIZE; 2045aefb655Srie prf.pr_fd = dbg_fd; 2055aefb655Srie 2067c478bd9Sstevel@tonic-gate /* 2075aefb655Srie * The getpid() call is a 'special' interface between ld.so.1 and dbx, 2085aefb655Srie * because of this getpid() can't be called freely until after control 2095aefb655Srie * has been given to the user program. Once the control has been given 2105aefb655Srie * to the user program we know that the r_debug structure has been 2115aefb655Srie * properly initialized for the debugger. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) 2147c478bd9Sstevel@tonic-gate _pid = getpid(); 2157c478bd9Sstevel@tonic-gate else 2167c478bd9Sstevel@tonic-gate _pid = pid; 2177c478bd9Sstevel@tonic-gate 2185aefb655Srie if (lml) 2195aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 2207c478bd9Sstevel@tonic-gate else 2215aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 2225aefb655Srie prf.pr_cur--; 2235aefb655Srie 2245aefb655Srie if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 2255aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 2265aefb655Srie prf.pr_cur--; 2275aefb655Srie } 2285aefb655Srie if (rtld_flags & RT_FL_THREADS) { 2295aefb655Srie (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 2305aefb655Srie prf.pr_cur--; 2315aefb655Srie } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * Format the message and print it. 2357c478bd9Sstevel@tonic-gate */ 2367c478bd9Sstevel@tonic-gate va_start(args, format); 2377c478bd9Sstevel@tonic-gate (void) doprf(format, args, &prf); 2387c478bd9Sstevel@tonic-gate *(prf.pr_cur - 1) = '\n'; 2397c478bd9Sstevel@tonic-gate (void) dowrite(&prf); 2407c478bd9Sstevel@tonic-gate va_end(args); 2417c478bd9Sstevel@tonic-gate } 242