1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Add experimental (and undocumented) --help-verbose and --help-short options.

This commit is contained in:
Markus F.X.J. Oberhumer 2024-04-21 14:20:18 +02:00
parent eb3c55b5cb
commit 9d26713b1a
9 changed files with 105 additions and 49 deletions

View File

@ -436,9 +436,13 @@ include(CTest)
if(NOT CMAKE_CROSSCOMPILING OR CMAKE_CROSSCOMPILING_EMULATOR)
add_test(NAME upx-version COMMAND upx --version)
add_test(NAME upx-version-short COMMAND upx --version-short)
add_test(NAME upx-help COMMAND upx --help)
add_test(NAME upx-license COMMAND upx --license)
add_test(NAME upx-sysinfo COMMAND upx --sysinfo -v)
add_test(NAME upx-help-1 COMMAND upx --help)
add_test(NAME upx-help-2 COMMAND upx --help-short)
add_test(NAME upx-help-3 COMMAND upx --help-verbose)
add_test(NAME upx-sysinfo-1 COMMAND upx --sysinfo)
add_test(NAME upx-sysinfo-2 COMMAND upx --sysinfo -v)
add_test(NAME upx-sysinfo-3 COMMAND upx --sysinfo -vv)
if(NOT UPX_CONFIG_DISABLE_SELF_PACK_TEST)
# IMPORTANT NOTE: these tests can only work if the host executable format is supported by UPX!
set(emu "")

View File

@ -25,6 +25,7 @@ if [[ -z $upx_exe ]]; then echo "UPX-ERROR: please set \$upx_exe"; exit 1; fi
if [[ ! -f $upx_exe ]]; then echo "UPX-ERROR: file '$upx_exe' does not exist"; exit 1; fi
upx_exe=$(readlink -fn "$upx_exe") # make absolute
[[ -f $upx_exe ]] || exit 1
# set emu and run_upx
emu=()
if [[ -n $upx_exe_runner ]]; then
@ -67,9 +68,13 @@ export UPX="--no-color --no-progress"
"${run_upx[@]}" --version
"${run_upx[@]}" --version-short
"${run_upx[@]}" --help
"${run_upx[@]}" --license
"${run_upx[@]}" --help
"${run_upx[@]}" --help-short
"${run_upx[@]}" --help-verbose
"${run_upx[@]}" --sysinfo
"${run_upx[@]}" --sysinfo -v
"${run_upx[@]}" --sysinfo -vv
if [[ $UPX_CONFIG_DISABLE_SELF_PACK_TEST == ON ]]; then
echo "Self-pack test disabled. All done."; exit 0

View File

@ -40,6 +40,7 @@ if [[ -z $upx_exe ]]; then echo "UPX-ERROR: please set \$upx_exe"; exit 1; fi
if [[ ! -f $upx_exe ]]; then echo "UPX-ERROR: file '$upx_exe' does not exist"; exit 1; fi
upx_exe=$(readlink -fn "$upx_exe") # make absolute
[[ -f $upx_exe ]] || exit 1
# set emu and run_upx
emu=()
if [[ -n $upx_exe_runner ]]; then

View File

@ -29,6 +29,7 @@ if [[ -z $upx_exe ]]; then echo "UPX-ERROR: please set \$upx_exe"; exit 1; fi
if [[ ! -f $upx_exe ]]; then echo "UPX-ERROR: file '$upx_exe' does not exist"; exit 1; fi
upx_exe=$(readlink -fn "$upx_exe") # make absolute
[[ -f $upx_exe ]] || exit 1
# set emu and run_upx
emu=()
if [[ -n $upx_exe_runner ]]; then
@ -43,7 +44,7 @@ fi
run_upx=( "${emu[@]}" "$upx_exe" )
echo "run_upx='${run_upx[*]}'"
# run_upx sanity check, part1
# run_upx sanity check
if ! "${run_upx[@]}" --version-short >/dev/null; then echo "UPX-ERROR: FATAL: upx --version-short FAILED"; exit 1; fi
if ! "${run_upx[@]}" -L >/dev/null 2>&1; then echo "UPX-ERROR: FATAL: upx -L FAILED"; exit 1; fi
if ! "${run_upx[@]}" --help >/dev/null; then echo "UPX-ERROR: FATAL: upx --help FAILED"; exit 1; fi
@ -75,19 +76,30 @@ fi
mkdir -p "$upx_testsuite_BUILDDIR" || exit 1
upx_testsuite_BUILDDIR=$(readlink -fn "$upx_testsuite_BUILDDIR") # make absolute
[[ -d $upx_testsuite_BUILDDIR ]] || exit 1
cd / && cd "$upx_testsuite_BUILDDIR" || exit 1
: > ./.mfxnobackup
# run_upx sanity check, part2
# run_upx sanity check after "cd"
if ! "${run_upx[@]}" --version-short >/dev/null; then
echo "UPX-ERROR: FATAL: upx --version-short FAILED"
echo "please make sure that \$upx_exe contains ABSOLUTE file paths and can be run from any directory"
echo "INFO: run_upx='${run_upx[*]}'"
exit 1
fi
if ! "${run_upx[@]}" -L >/dev/null 2>&1; then echo "UPX-ERROR: FATAL: upx -L FAILED"; exit 1; fi
if ! "${run_upx[@]}" --help >/dev/null; then echo "UPX-ERROR: FATAL: upx --help FAILED"; exit 1; fi
#***********************************************************************
# setup
#***********************************************************************
#set -x # debug
exit_code=0
num_errors=0
all_errors=
export UPX="--prefer-ucl --no-color --no-progress"
export UPX_DEBUG_DISABLE_GITREV_WARNING=1
export UPX_DEBUG_DOCTEST_VERBOSE=0
case $UPX_TESTSUITE_LEVEL in
[0-8]) ;;
@ -98,19 +110,6 @@ if [[ $UPX_TESTSUITE_LEVEL == 0 ]]; then
exit 0
fi
#***********************************************************************
# setup
#***********************************************************************
#set -x # debug
exit_code=0
num_errors=0
all_errors=
export UPX="--prefer-ucl --no-color --no-progress"
export UPX_DEBUG_DISABLE_GITREV_WARNING=1
export UPX_DEBUG_DOCTEST_VERBOSE=0
rm -rf ./testsuite_1
mkdir testsuite_1 || exit 1
cd testsuite_1 || exit 1

View File

@ -822,7 +822,7 @@ int do_files(int i, int argc, char *argv[]) may_throw;
// help.cpp
extern const char gitrev[];
void show_header();
void show_help(int verbose = 0);
void show_help(int verbose);
void show_license();
void show_sysinfo(const char *options_var);
void show_usage();

View File

@ -34,6 +34,7 @@ static constexpr long long initial_win32_winnt = 0;
#include "conf.h"
#include "compress/compress.h" // upx_ucl_version_string()
// for list_all_packers():
#include "filter.h" // Filter::isValidFilter
#include "packer.h"
#include "packmast.h" // PackMaster::visitAllPackers
@ -101,48 +102,85 @@ void show_usage(void) {
namespace {
struct PackerNames final {
PackerNames() noexcept = default;
explicit PackerNames() noexcept = default;
~PackerNames() noexcept = default;
static constexpr size_t MAX_NAMES = 64;
static constexpr size_t MAX_METHODS = 8;
static constexpr size_t MAX_FILTERS = 16;
struct Entry {
const char *fname;
const char *sname;
size_t methods_count;
size_t filters_count;
unsigned methods[MAX_METHODS];
unsigned filters[MAX_FILTERS];
};
static constexpr size_t MAX_NAMES = 64;
Entry names[MAX_NAMES];
size_t names_count = 0;
const Options *o = nullptr;
void add(const PackerBase *pb) {
assert_noexcept(names_count < MAX_NAMES);
names[names_count].fname = pb->getFullName(o);
names[names_count].sname = pb->getName();
names_count++;
Entry &e = names[names_count++];
e.fname = pb->getFullName(o);
e.sname = pb->getName();
e.methods_count = e.filters_count = 0;
for (const int *m = pb->getCompressionMethods(M_ALL, 10); *m != M_END; m++) {
if (*m >= 0) {
assert_noexcept(Packer::isValidCompressionMethod(*m));
assert_noexcept(e.methods_count < MAX_METHODS);
e.methods[e.methods_count++] = *m;
}
}
for (const int *f = pb->getFilters(); f != nullptr && *f != FT_END; f++) {
if (*f >= 0) {
assert_noexcept(Filter::isValidFilter(*f));
assert_noexcept(e.filters_count < MAX_FILTERS);
e.filters[e.filters_count++] = *f;
}
}
upx_gnomesort(e.methods, e.methods_count, sizeof(e.methods[0]), ne32_compare);
upx_gnomesort(e.filters, e.filters_count, sizeof(e.filters[0]), ne32_compare);
}
static tribool visit(PackerBase *pb, void *user) {
NO_fprintf(stderr, "visit %s\n", pb->getFullName(nullptr));
PackerNames *self = (PackerNames *) user;
self->add(pb);
return false;
}
static int __acc_cdecl_qsort cmp_fname(const void *a, const void *b) {
static int __acc_cdecl_qsort compare_fname(const void *a, const void *b) {
return strcmp(((const Entry *) a)->fname, ((const Entry *) b)->fname);
}
static int __acc_cdecl_qsort cmp_sname(const void *a, const void *b) {
static int __acc_cdecl_qsort compare_sname(const void *a, const void *b) {
return strcmp(((const Entry *) a)->sname, ((const Entry *) b)->sname);
}
};
} // namespace
static void list_all_packers(FILE *f, int verbose) {
static noinline void list_all_packers(FILE *f, int verbose) {
Options o;
o.reset();
PackerNames pn;
pn.o = &o;
(void) PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn);
upx_qsort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::cmp_fname);
upx_gnomesort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::compare_fname);
size_t pos = 0;
for (size_t i = 0; i < pn.names_count; ++i) {
const char *fn = pn.names[i].fname;
const char *sn = pn.names[i].sname;
if (verbose > 0) {
for (size_t i = 0; i < pn.names_count; i++) {
const PackerNames::Entry &e = pn.names[i];
const char *const fn = e.fname;
const char *const sn = e.sname;
if (verbose >= 3) {
con_fprintf(f, " %-36s %s\n", fn, sn);
con_fprintf(f, " methods:");
for (size_t j = 0; j < e.methods_count; j++)
con_fprintf(f, " %#x", e.methods[j]);
con_fprintf(f, "\n");
con_fprintf(f, " filters:");
for (size_t j = 0; j < e.filters_count; j++)
con_fprintf(f, " %#x", e.filters[j]);
con_fprintf(f, "\n");
} else if (verbose >= 2) {
con_fprintf(f, " %-36s %s\n", fn, sn);
} else {
size_t fl = strlen(fn);
@ -158,7 +196,7 @@ static void list_all_packers(FILE *f, int verbose) {
}
}
}
if (verbose <= 0 && pn.names_count)
if (verbose < 2 && pn.names_count)
con_fprintf(f, "\n");
}

View File

@ -218,7 +218,7 @@ static void check_and_update_options(int i, int argc) {
**************************************************************************/
static void e_help(void) {
show_help();
show_help(0);
e_exit(EXIT_USAGE);
}
@ -386,6 +386,8 @@ static int do_option(int optc, const char *arg) {
set_cmd(CMD_HELP);
break;
case 'h' + 256:
case 996:
case 997:
#if 1
if (!acc_isatty(STDOUT_FILENO)) {
/* according to GNU standards */
@ -393,7 +395,7 @@ static int do_option(int optc, const char *arg) {
opt->console = CON_FILE;
}
#endif
show_help(1);
show_help(optc == 996 ? 1 : (optc == 997 ? 3 : 2));
e_exit(EXIT_OK);
break;
case 'i':
@ -1172,9 +1174,14 @@ static void first_options(int argc, char **argv) {
if (strcmp(argv[i], "--version-short") == 0)
do_option(998, argv[i]);
}
for (i = 1; i < n; i++)
for (i = 1; i < n; i++) {
if (strcmp(argv[i], "--help") == 0)
do_option('h' + 256, argv[i]);
if (strcmp(argv[i], "--help-short") == 0) // undocumented and subject to change
do_option(996, argv[i]);
if (strcmp(argv[i], "--help-verbose") == 0) // undocumented and subject to change
do_option(997, argv[i]);
}
for (i = 1; i < n; i++)
if (strcmp(argv[i], "--no-env") == 0)
do_option(519, argv[i]);
@ -1272,7 +1279,7 @@ int upx_main(int argc, char *argv[]) may_throw {
e_exit(EXIT_OK);
break;
case CMD_HELP:
show_help(1);
show_help(2);
e_exit(EXIT_OK);
break;
case CMD_LICENSE:

View File

@ -58,8 +58,10 @@ void Packer::assertPacker() const {
assert(getVersion() <= 14);
assert(strlen(getName()) <= 15);
// info: 36 is the limit for show_all_packers() in help.cpp, but 32 should be enough
assert(strlen(getFullName(opt)) <= 32);
assert(strlen(getFullName(nullptr)) <= 32);
assert(strlen(getFullName(opt)) <= 32);
assert(getCompressionMethods(M_ALL, 10) != nullptr);
(void) getFilters();
if (bele == nullptr)
fprintf(stderr, "%s\n", getName());
assert(bele != nullptr);

View File

@ -293,13 +293,13 @@ static inline void memswap_no_overlap(byte *a, byte *b, size_t bytes) noexcept {
upx_memswap(a, b, bytes);
#else // clang bug
upx_alignas_max byte tmp_buf[16];
#define SWAP(x) \
#define SWAP(n) \
do { \
upx_memcpy_inline(tmp_buf, a, x); \
upx_memcpy_inline(a, b, x); \
upx_memcpy_inline(b, tmp_buf, x); \
a += x; \
b += x; \
upx_memcpy_inline(tmp_buf, a, n); \
upx_memcpy_inline(a, b, n); \
upx_memcpy_inline(b, tmp_buf, n); \
a += n; \
b += n; \
} while (0)
for (; bytes >= 16; bytes -= 16)
@ -382,7 +382,7 @@ void upx_shellsort_memcpy(void *array, size_t n, size_t element_size, upx_compar
// wrap std::stable_sort()
template <size_t ElementSize>
void upx_std_stable_sort(void *array, size_t n, upx_compare_func_t compare) {
static_assert(ElementSize > 0 && ElementSize <= UPX_RSIZE_MAX);
static_assert(ElementSize >= 1 && ElementSize <= UPX_RSIZE_MAX);
mem_size_assert(ElementSize, n); // check size
#if 0
// just for testing
@ -412,7 +412,7 @@ template void upx_std_stable_sort<16>(void *, size_t, upx_compare_func_t);
template void upx_std_stable_sort<32>(void *, size_t, upx_compare_func_t);
template void upx_std_stable_sort<56>(void *, size_t, upx_compare_func_t);
template void upx_std_stable_sort<72>(void *, size_t, upx_compare_func_t);
#endif
#endif // UPX_CONFIG_USE_STABLE_SORT
#if !defined(DOCTEST_CONFIG_DISABLE) && DEBUG
#if __cplusplus >= 202002L // use C++20 std::next_permutation() to test all permutations