diff options
author | Florian Weimer <fweimer@redhat.com> | 2020-10-08 10:57:10 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2020-10-08 15:00:39 +0200 |
commit | e0f1a58f3d1f4f55591b524e9dcff23cc98a509e (patch) | |
tree | cd744b7405d8793811595fc9d7020ef354e1e2d6 /elf/rtld.c | |
parent | 27316f4a23efdc90bdfe4569a6c4b7e27941606e (diff) | |
download | glibc-e0f1a58f3d1f4f55591b524e9dcff23cc98a509e.tar.gz glibc-e0f1a58f3d1f4f55591b524e9dcff23cc98a509e.tar.xz glibc-e0f1a58f3d1f4f55591b524e9dcff23cc98a509e.zip |
elf: Implement ld.so --help
--help processing is deferred to the point where the executable has been loaded, so that it is possible to eventually include information from the main executable in the help output. As suggested in the GNU command-line interface guidelines, the help message is printed to standard output, and the exit status is successful. Handle usage errors closer to the GNU command-line interface guidelines. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'elf/rtld.c')
-rw-r--r-- | elf/rtld.c | 56 |
1 files changed, 48 insertions, 8 deletions
diff --git a/elf/rtld.c b/elf/rtld.c index c0609e4310..2eeec981a5 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1151,6 +1151,7 @@ dl_main (const ElfW(Phdr) *phdr, _dl_starting_up = 1; #endif + const char *ld_so_name = _dl_argv[0]; if (*user_entry == (ElfW(Addr)) ENTRY_POINT) { /* Ho ho. We are not the program interpreter! We are the program @@ -1178,8 +1179,12 @@ dl_main (const ElfW(Phdr) *phdr, while (_dl_argc > 1) if (! strcmp (_dl_argv[1], "--list")) { - state.mode = rtld_mode_list; - GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */ + if (state.mode != rtld_mode_help) + { + state.mode = rtld_mode_list; + /* This means do no dependency analysis. */ + GLRO(dl_lazy) = -1; + } ++_dl_skip_args; --_dl_argc; @@ -1187,7 +1192,8 @@ dl_main (const ElfW(Phdr) *phdr, } else if (! strcmp (_dl_argv[1], "--verify")) { - state.mode = rtld_mode_verify; + if (state.mode != rtld_mode_help) + state.mode = rtld_mode_verify; ++_dl_skip_args; --_dl_argc; @@ -1242,13 +1248,34 @@ dl_main (const ElfW(Phdr) *phdr, _dl_argc -= 2; _dl_argv += 2; } + else if (strcmp (_dl_argv[1], "--help") == 0) + { + state.mode = rtld_mode_help; + --_dl_argc; + ++_dl_argv; + } + else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-') + { + if (_dl_argv[1][1] == '\0') + /* End of option list. */ + break; + else + /* Unrecognized option. */ + _dl_usage (ld_so_name, _dl_argv[1]); + } else break; /* If we have no further argument the program was called incorrectly. Grant the user some education. */ if (_dl_argc < 2) - _dl_usage (); + { + if (state.mode == rtld_mode_help) + /* --help without an executable is not an error. */ + _dl_help (ld_so_name, &state); + else + _dl_usage (ld_so_name, NULL); + } ++_dl_skip_args; --_dl_argc; @@ -1273,7 +1300,8 @@ dl_main (const ElfW(Phdr) *phdr, break; } - if (__glibc_unlikely (state.mode == rtld_mode_verify)) + if (__glibc_unlikely (state.mode == rtld_mode_verify + || state.mode == rtld_mode_help)) { const char *objname; const char *err_str = NULL; @@ -1286,9 +1314,16 @@ dl_main (const ElfW(Phdr) *phdr, (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit, &args); if (__glibc_unlikely (err_str != NULL)) - /* We don't free the returned string, the programs stops - anyway. */ - _exit (EXIT_FAILURE); + { + /* We don't free the returned string, the programs stops + anyway. */ + if (state.mode == rtld_mode_help) + /* Mask the failure to load the main object. The help + message contains less information in this case. */ + _dl_help (ld_so_name, &state); + else + _exit (EXIT_FAILURE); + } } else { @@ -1647,6 +1682,11 @@ dl_main (const ElfW(Phdr) *phdr, audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); + /* At this point, all data has been obtained that is included in the + --help output. */ + if (__glibc_unlikely (state.mode == rtld_mode_help)) + _dl_help (ld_so_name, &state); + /* If we have auditing DSOs to load, do it now. */ bool need_security_init = true; if (state.audit_list.length > 0) |