1/* Print diagnostics data in ld.so.
2 Copyright (C) 2021-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <gnu/lib-names.h>
20#include <stdbool.h>
21#include <stddef.h>
22#include <unistd.h>
23
24#include <dl-diagnostics.h>
25#include <dl-hwcaps.h>
26#include <dl-main.h>
27#include <dl-procinfo.h>
28#include <dl-sysdep.h>
29#include <ldsodefs.h>
30#include "trusted-dirs.h"
31#include "version.h"
32
33/* Write CH to standard output. */
34static void
35_dl_putc (char ch)
36{
37 _dl_write (STDOUT_FILENO, buffer: &ch, length: 1);
38}
39
40/* Print CH to standard output, quoting it if necessary. */
41static void
42print_quoted_char (char ch)
43{
44 if (ch < ' ' || ch > '~')
45 {
46 char buf[4];
47 buf[0] = '\\';
48 buf[1] = '0' + ((ch >> 6) & 7);
49 buf[2] = '0' + ((ch >> 6) & 7);
50 buf[3] = '0' + (ch & 7);
51 _dl_write (STDOUT_FILENO, buffer: buf, length: 4);
52 }
53 else
54 {
55 if (ch == '\\' || ch == '"')
56 _dl_putc (ch: '\\');
57 _dl_putc (ch);
58 }
59}
60
61/* Print S of LEN bytes to standard output, quoting characters as
62 needed. */
63static void
64print_string_length (const char *s, size_t len)
65{
66 _dl_putc (ch: '"');
67 for (size_t i = 0; i < len; ++i)
68 print_quoted_char (ch: s[i]);
69 _dl_putc (ch: '"');
70}
71
72void
73_dl_diagnostics_print_string (const char *s)
74{
75 if (s == NULL)
76 {
77 _dl_printf (fmt: "0x0");
78 return;
79 }
80
81 _dl_putc (ch: '"');
82 while (*s != '\0')
83 {
84 print_quoted_char (ch: *s);
85 ++s;
86 }
87 _dl_putc (ch: '"');
88}
89
90void
91_dl_diagnostics_print_labeled_string (const char *label, const char *s)
92{
93 _dl_printf (fmt: "%s=", label);
94 _dl_diagnostics_print_string (s);
95 _dl_putc (ch: '\n');
96}
97
98void
99_dl_diagnostics_print_labeled_value (const char *label, uint64_t value)
100{
101 if (sizeof (value) == sizeof (unsigned long int))
102 /* _dl_printf can print 64-bit values directly. */
103 _dl_printf (fmt: "%s=0x%lx\n", label, (unsigned long int) value);
104 else
105 {
106 uint32_t high = value >> 32;
107 uint32_t low = value;
108 if (high == 0)
109 _dl_printf (fmt: "%s=0x%x\n", label, low);
110 else
111 _dl_printf (fmt: "%s=0x%x%08x\n", label, high, low);
112 }
113}
114
115/* Return true if ENV is an unfiltered environment variable. */
116static bool
117unfiltered_envvar (const char *env, size_t *name_length)
118{
119 char *env_equal = strchr (env, '=');
120 if (env_equal == NULL)
121 {
122 /* Always dump malformed entries. */
123 *name_length = strlen (env);
124 return true;
125 }
126 size_t envname_length = env_equal - env;
127 *name_length = envname_length;
128
129 /* LC_ and LD_ variables. */
130 if (env[0] == 'L' && (env[1] == 'C' || env[1] == 'D')
131 && env[2] == '_')
132 return true;
133
134 /* MALLOC_ variables. */
135 if (strncmp (s1: env, s2: "MALLOC_", n: strlen ("MALLOC_")) == 0)
136 return true;
137
138 static const char unfiltered[] =
139 "DATEMSK\0"
140 "GCONV_PATH\0"
141 "GETCONF_DIR\0"
142 "GETCONF_DIR\0"
143 "GLIBC_TUNABLES\0"
144 "GMON_OUTPUT_PREFIX\0"
145 "HESIOD_CONFIG\0"
146 "HES_DOMAIN\0"
147 "HOSTALIASES\0"
148 "I18NPATH\0"
149 "IFS\0"
150 "LANG\0"
151 "LOCALDOMAIN\0"
152 "LOCPATH\0"
153 "MSGVERB\0"
154 "NIS_DEFAULTS\0"
155 "NIS_GROUP\0"
156 "NIS_PATH\0"
157 "NLSPATH\0"
158 "PATH\0"
159 "POSIXLY_CORRECT\0"
160 "RESOLV_HOST_CONF\0"
161 "RES_OPTIONS\0"
162 "SEV_LEVEL\0"
163 "TMPDIR\0"
164 "TZ\0"
165 "TZDIR\0"
166 /* Two null bytes at the end to mark the end of the list via an
167 empty substring. */
168 ;
169 for (const char *candidate = unfiltered; *candidate != '\0'; )
170 {
171 size_t candidate_length = strlen (candidate);
172 if (candidate_length == envname_length
173 && memcmp (candidate, env, candidate_length) == 0)
174 return true;
175 candidate += candidate_length + 1;
176 }
177
178 return false;
179}
180
181/* Dump the process environment. */
182static void
183print_environ (char **environ)
184{
185 unsigned int index = 0;
186 for (char **envp = environ; *envp != NULL; ++envp)
187 {
188 char *env = *envp;
189 size_t name_length;
190 bool unfiltered = unfiltered_envvar (env, name_length: &name_length);
191 _dl_printf (fmt: "env%s[0x%x]=",
192 unfiltered ? "" : "_filtered", index);
193 if (unfiltered)
194 _dl_diagnostics_print_string (s: env);
195 else
196 print_string_length (s: env, len: name_length);
197 _dl_putc (ch: '\n');
198 ++index;
199 }
200}
201
202/* Print configured paths and the built-in search path. */
203static void
204print_paths (void)
205{
206 _dl_diagnostics_print_labeled_string (label: "path.prefix", PREFIX);
207 _dl_diagnostics_print_labeled_string (label: "path.rtld", RTLD);
208 _dl_diagnostics_print_labeled_string (label: "path.sysconfdir", SYSCONFDIR);
209
210 unsigned int index = 0;
211 static const char *system_dirs = SYSTEM_DIRS "\0";
212 for (const char *e = system_dirs; *e != '\0'; )
213 {
214 size_t len = strlen (e);
215 _dl_printf (fmt: "path.system_dirs[0x%x]=", index);
216 print_string_length (s: e, len);
217 _dl_putc (ch: '\n');
218 ++index;
219 e += len + 1;
220 }
221}
222
223/* Print information about the glibc version. */
224static void
225print_version (void)
226{
227 _dl_diagnostics_print_labeled_string (label: "version.release", RELEASE);
228 _dl_diagnostics_print_labeled_string (label: "version.version", VERSION);
229}
230
231void
232_dl_print_diagnostics (char **environ)
233{
234#ifdef HAVE_DL_DISCOVER_OSVERSION
235 _dl_diagnostics_print_labeled_value
236 (label: "dl_discover_osversion", value: _dl_discover_osversion ());
237#endif
238 _dl_diagnostics_print_labeled_string (label: "dl_dst_lib", s: DL_DST_LIB);
239 _dl_diagnostics_print_labeled_value (label: "dl_hwcap", GLRO (dl_hwcap));
240 _dl_diagnostics_print_labeled_value (label: "dl_hwcap_important", HWCAP_IMPORTANT);
241 _dl_diagnostics_print_labeled_value (label: "dl_hwcap2", GLRO (dl_hwcap2));
242 _dl_diagnostics_print_labeled_string
243 (label: "dl_hwcaps_subdirs", s: _dl_hwcaps_subdirs);
244 _dl_diagnostics_print_labeled_value
245 (label: "dl_hwcaps_subdirs_active", value: _dl_hwcaps_subdirs_active ());
246 _dl_diagnostics_print_labeled_value (label: "dl_osversion", GLRO (dl_osversion));
247 _dl_diagnostics_print_labeled_value (label: "dl_pagesize", GLRO (dl_pagesize));
248 _dl_diagnostics_print_labeled_string (label: "dl_platform", GLRO (dl_platform));
249 _dl_diagnostics_print_labeled_string
250 (label: "dl_profile_output", GLRO (dl_profile_output));
251 _dl_diagnostics_print_labeled_value
252 (label: "dl_string_platform", value: _dl_string_platform ( GLRO (dl_platform)));
253
254 _dl_diagnostics_print_labeled_string (label: "dso.ld", LD_SO);
255 _dl_diagnostics_print_labeled_string (label: "dso.libc", LIBC_SO);
256
257 print_environ (environ);
258 print_paths ();
259 print_version ();
260
261 _dl_diagnostics_kernel ();
262 _dl_diagnostics_cpu ();
263
264 _exit (EXIT_SUCCESS);
265}
266

source code of glibc/elf/dl-diagnostics.c