4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <sys/types.h>
47 * Routines for dumping alternate objects under CRLE_AUD_DLDUMP mode.
49 static Addr membgn
= 0;
50 static Addr memend
= 0;
53 * For each file in the configuration file that requires an alternate (dldump())
54 * version, add the object to the processes main link-map. The process head
55 * may be an application, shared object, or lddstub. In any case this object
56 * may be augmented with other objects defined within the configuration file.
58 * Each file is initially loaded with RTLD_CONFGEN so that no dependency
59 * analysis, relocation, or user code (.init's) is executed. By skipping
60 * analysis we save time and allow for a family of objects to be dumped that
61 * may not have all relocations satisfied. If necessary, a later call to
62 * dlopen() using RTLD_NOW will force relocations to occur.
64 * A mapping range is maintained to span the mapping of each objects, and this
65 * range is finally written back to the caller.
69 load(const char *opath
, const char *npath
)
73 Addr _membgn
, _memend
;
75 if ((ghp
= (Grp_hdl
*)dlmopen(LM_ID_BASE
, opath
,
76 (RTLD_LAZY
| RTLD_GLOBAL
| RTLD_CONFGEN
))) == NULL
) {
77 (void) fprintf(stderr
, MSG_INTL(MSG_DL_OPEN
),
78 MSG_ORIG(MSG_FIL_LIBCRLE
), dlerror());
82 FLAGS1(lmp
) |= FL1_RT_CONFSET
;
85 * Establish the mapping range of the objects dumped so far.
88 _memend
= (ADDR(lmp
) + MSIZE(lmp
));
103 * dldump(3x) an object that is already part of the main link-map list.
106 dump(const char *opath
, const char *npath
)
108 (void) unlink(npath
);
110 if (dldump(opath
, npath
, dlflag
) != 0) {
111 (void) fprintf(stderr
, MSG_INTL(MSG_DL_DUMP
),
112 MSG_ORIG(MSG_FIL_LIBCRLE
), dlerror());
119 * Traverse a configuration file directory/file list. Each file within the
120 * list is maintained as both a full pathname and a simple filename - we're
121 * only interested in one.
123 * This rutine is called twice, once to insure the appropriate objects are
124 * mapped in (fptr == load()) and then once again to dldump(3x) the mapped
125 * objects (fptr == dump()).
128 scanconfig(Addr addr
, int (*fptr
)())
130 Rtc_head
* head
= (Rtc_head
*)addr
;
134 const char *str
, *strtbl
;
137 strtbl
= (const char *)((char *)addr
+ head
->ch_str
);
140 * Scan the directory and filename arrays looking for alternatives.
142 for (dirtbl
= (Rtc_dir
*)(head
->ch_dir
+ addr
);
143 dirtbl
->cd_obj
; dirtbl
++) {
145 obj
= (Rtc_obj
*)(dirtbl
->cd_obj
+ addr
);
146 str
= strtbl
+ obj
->co_name
;
148 if (obj
->co_flags
& RTC_OBJ_NOEXIST
)
151 for (filetbl
= (Rtc_file
*)(dirtbl
->cd_file
+ addr
);
152 filetbl
->cf_obj
; filetbl
++) {
154 obj
= (Rtc_obj
*)(filetbl
->cf_obj
+ addr
);
155 str
= strtbl
+ obj
->co_name
;
158 (RTC_OBJ_DUMP
| RTC_OBJ_REALPTH
| RTC_OBJ_EXEC
)) ==
159 (RTC_OBJ_DUMP
| RTC_OBJ_REALPTH
)) {
160 if ((*fptr
)(str
, strtbl
+ obj
->co_alter
) != 0)
167 * Are we dumping a specific application.
174 * Obtain a handle to the application and set the
175 * FL1_RT_CONFSET flag.
177 if ((ghp
= dlmopen(LM_ID_BASE
, 0,
178 (RTLD_NOLOAD
| RTLD_CONFGEN
))) == 0)
180 FLAGS1(ghp
->gh_ownlmp
) |= FL1_RT_CONFSET
;
184 * If we're dumping and this configuration is for a
185 * specific application dump it also.
188 obj
= (Rtc_obj
*)((char *)addr
+ head
->ch_app
);
189 str
= strtbl
+ obj
->co_alter
;
191 if (dump((const char *)0, str
) != 0)
200 * Before loading any dependencies determine the present memory mappings being
201 * used and fill any holes between these mappings. This insures that all
202 * dldump()'ed dependencies will live in a single consecutive address range.
207 prmap_t
*maps
, *_maps
;
209 int fd
= 0, err
, num
, _num
;
210 size_t size
, syspagsz
;
211 uintptr_t laddr
= 0, saddr
;
215 * Open /proc/self/status to determine the virtual address of the
218 if ((fd
= open(MSG_ORIG(MSG_PTH_PROCSTATUS
), O_RDONLY
)) == -1) {
220 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
221 MSG_ORIG(MSG_FIL_LIBCRLE
), MSG_ORIG(MSG_PTH_PROCSTATUS
),
225 if (read(fd
, &prstatus
, sizeof (pstatus_t
)) != sizeof (pstatus_t
)) {
227 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_READ
),
228 MSG_ORIG(MSG_FIL_LIBCRLE
), MSG_ORIG(MSG_PTH_PROCSTATUS
),
236 * Round the process heap to the next page boundary so that it can be
237 * used to isolated the a.out mappings (pr_brkbase typically occurs
238 * at the end, but within, the a.out's data segment). As libcrle is
239 * used as an audit library, no process user code has run so there
240 * can't be any heap. pr_brksize is added here for completeness.
242 syspagsz
= sysconf(_SC_PAGESIZE
);
243 saddr
= M_PROUND(prstatus
.pr_brkbase
+ prstatus
.pr_brksize
);
246 * Open /proc/self/rmap to obtain the processes reserved mappings.
248 if ((fd
= open(MSG_ORIG(MSG_PTH_PROCRMAP
), O_RDONLY
)) == -1) {
250 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
251 MSG_ORIG(MSG_FIL_LIBCRLE
), MSG_ORIG(MSG_PTH_PROCRMAP
),
255 (void) fstat(fd
, &status
);
258 * Determine number of mappings - use alloca so as not to perturb any
259 * mapping information by a malloc, which itself might add a mapping.
262 num
= (int)(status
.st_size
/ sizeof (prmap_t
));
263 size
= num
* sizeof (prmap_t
);
265 if ((maps
= alloca(size
)) == 0) {
266 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_ALLOC
),
267 MSG_ORIG(MSG_FIL_LIBCRLE
), strerror(ENOMEM
));
272 if (read(fd
, (void *)maps
, size
) < 0) {
274 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_READ
),
275 MSG_ORIG(MSG_FIL_LIBCRLE
), MSG_ORIG(MSG_PTH_PROCRMAP
),
283 * Use /dev/null for filling holes.
285 if ((fd
= open(MSG_ORIG(MSG_PTH_DEVNULL
), O_RDONLY
)) == -1) {
287 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
288 MSG_ORIG(MSG_FIL_LIBCRLE
), MSG_ORIG(MSG_PTH_DEVNULL
),
294 * Scan each mapping - note it is assummed that the mappings are
295 * presented in order. We fill holes between mappings. On intel
296 * the last mapping is usually the data segment of ld.so.1, after
297 * this comes a red zone into which non-fixed mapping won't get
298 * place. Thus we can simply bail from the loop after seeing the
301 for (_num
= 0, _maps
= maps
; _num
< num
; _num
++, _maps
++) {
303 * Skip all mappings below brkbase, these represent the a.out
304 * (and the stack on intel).
307 ((_maps
->pr_vaddr
+ _maps
->pr_size
) <= saddr
))
311 * For each consecutive mapping determine the hole between each
312 * and fill it from /dev/null.
315 laddr
= _maps
->pr_vaddr
+ _maps
->pr_size
;
319 if ((size
= _maps
->pr_vaddr
- laddr
) != 0) {
320 if (mmap((void *)laddr
, size
, PROT_NONE
,
321 (MAP_FIXED
| MAP_PRIVATE
), fd
, 0) == MAP_FAILED
) {
323 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_MMAP
),
324 MSG_ORIG(MSG_FIL_LIBCRLE
),
325 MSG_ORIG(MSG_PTH_DEVNULL
), strerror(err
));
329 laddr
= _maps
->pr_vaddr
+ _maps
->pr_size
;
333 * It's been observed that there may be space between the end of the
334 * last mapping (typically ld.so.1), and the kernel base address. As
335 * there's no interface to determine the kernel base address, keep
336 * filling in pages until we get an error. We'll get ENOMEM once we
337 * hit the kernel base address.
340 if (mmap((void *)laddr
, syspagsz
, PROT_NONE
,
341 (MAP_FIXED
| MAP_PRIVATE
), fd
, 0) == MAP_FAILED
) {
345 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_MMAP
),
346 MSG_ORIG(MSG_FIL_LIBCRLE
),
347 MSG_ORIG(MSG_PTH_DEVNULL
), strerror(err
));
361 * Dump alternative objects as part of building a configuration file. A temp
362 * configuration is already built and made available to the process, and is
363 * located via dlinfo(). Having load()'ed each object, and dump()'ed its image,
364 * the final memory reservation infoamtion is returned to the caller.
369 char buffer
[PATH_MAX
];
374 * Determine the configuration file and where it is mapped.
376 if (dlinfo(NULL
, RTLD_DI_CONFIGADDR
, &info
) == -1) {
377 (void) fprintf(stderr
, MSG_INTL(MSG_DL_INFO
),
378 MSG_ORIG(MSG_FIL_LIBCRLE
), dlerror());
381 config
= (Addr
)info
.dli_fbase
;
384 * Scan the configuration file for alternative entries.
386 if (scanconfig(config
, load
) != 0)
390 * Having mapped all objects, relocate them. It would be nice if we
391 * could drop this step altogether, and have dldump() carry out just
392 * those relocations required, but when binding to an application we
393 * need to handle copy relocations - these can affect bindings (in the
394 * case of things like libld.so which have direct bindings) and require
395 * that the data being copied is itself relocated.
397 if (dlmopen(LM_ID_BASE
, 0, (RTLD_NOW
| RTLD_CONFGEN
)) == 0)
401 * Rescan the configuration dumping out each alternative file.
403 if (scanconfig(config
, dump
) != 0)
407 * Having established the memory range of the dumped images and
408 * sucessfully dumped them out, report back to the caller.
410 (void) sprintf(buffer
, MSG_ORIG(MSG_AUD_RESBGN
), EC_ADDR(membgn
));
411 (void) write(pfd
, buffer
, strlen(buffer
));
413 (void) sprintf(buffer
, MSG_ORIG(MSG_AUD_RESEND
), EC_ADDR(memend
));
414 (void) write(pfd
, buffer
, strlen(buffer
));