[PATCH v3 1/2] tools/nolibc: add support for program_invocation_{,short_}name

Thomas Weißschuh posted 2 patches 3 weeks ago
There is a newer version of this series
[PATCH v3 1/2] tools/nolibc: add support for program_invocation_{,short_}name
Posted by Thomas Weißschuh 3 weeks ago
Add support for the GNU extensions 'program_invocation_name' and
'program_invocation_short_name'. These are useful to print error
messages, which by convention include the program name.

As these are global variables which take up memory even if not used,
similar to 'errno', gate them behind NOLIBC_IGNORE_ERRNO.

Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
 tools/include/nolibc/crt.h                   | 26 ++++++++++++++++++++++
 tools/include/nolibc/errno.h                 |  4 ++++
 tools/testing/selftests/nolibc/nolibc-test.c | 33 ++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h
index d9262998dae9..5bb492555f13 100644
--- a/tools/include/nolibc/crt.h
+++ b/tools/include/nolibc/crt.h
@@ -17,6 +17,7 @@ const unsigned long *_auxv __attribute__((weak));
 void _start(void);
 static void __stack_chk_init(void);
 static void exit(int);
+static char *strrchr(const char *s, int c);
 
 extern void (*const __preinit_array_start[])(int, char **, char**) __attribute__((weak));
 extern void (*const __preinit_array_end[])(int, char **, char**) __attribute__((weak));
@@ -27,6 +28,24 @@ extern void (*const __init_array_end[])(int, char **, char**) __attribute__((wea
 extern void (*const __fini_array_start[])(void) __attribute__((weak));
 extern void (*const __fini_array_end[])(void) __attribute__((weak));
 
+#ifndef NOLIBC_IGNORE_ERRNO
+extern char *program_invocation_name __attribute__((weak));
+extern char *program_invocation_short_name __attribute__((weak));
+
+static __inline__
+char *__nolibc_program_invocation_short_name(char *long_name)
+{
+
+	char *short_name;
+
+	short_name = strrchr(long_name, '/');
+	if (!short_name || !short_name[0])
+		return long_name;
+
+	return short_name + 1;
+}
+#endif /* NOLIBC_IGNORE_ERRNO */
+
 void _start_c(long *sp);
 __attribute__((weak,used))
 #if __nolibc_has_feature(undefined_behavior_sanitizer)
@@ -76,6 +95,13 @@ void _start_c(long *sp)
 		;
 	_auxv = auxv;
 
+#ifndef NOLIBC_IGNORE_ERRNO
+	if (argc > 0 && argv[0]) {
+		program_invocation_name = argv[0];
+		program_invocation_short_name = __nolibc_program_invocation_short_name(argv[0]);
+	}
+#endif /* NOLIBC_IGNORE_ERRNO */
+
 	for (ctor_func = __preinit_array_start; ctor_func < __preinit_array_end; ctor_func++)
 		(*ctor_func)(argc, argv, envp);
 	for (ctor_func = __init_array_start; ctor_func < __init_array_end; ctor_func++)
diff --git a/tools/include/nolibc/errno.h b/tools/include/nolibc/errno.h
index 08a33c40ec0c..bab83692ea1c 100644
--- a/tools/include/nolibc/errno.h
+++ b/tools/include/nolibc/errno.h
@@ -15,8 +15,12 @@
 #ifndef NOLIBC_IGNORE_ERRNO
 #define SET_ERRNO(v) do { errno = (v); } while (0)
 int errno __attribute__((weak));
+char *program_invocation_name __attribute__((weak)) = "";
+char *program_invocation_short_name __attribute__((weak)) = "";
 #else
 #define SET_ERRNO(v) do { } while (0)
+#define program_invocation_name ""
+#define program_invocation_short_name ""
 #endif
 
 
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 180611aabbfb..07af23833879 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -702,6 +702,37 @@ static void constructor2(int argc, char **argv, char **envp)
 		constructor_test_value |= 1 << 1;
 }
 
+int test_program_invocation_name(void)
+{
+	char buf[100];
+	char *dirsep;
+	ssize_t r;
+	int fd;
+
+	fd = open("/proc/self/cmdline", O_RDONLY);
+	if (fd == -1)
+		return 1;
+
+	r = read(fd, buf, sizeof(buf));
+	close(fd);
+	if (r < 1 || r == sizeof(buf))
+		return 1;
+
+	buf[r - 1] = '\0';
+
+	if (strcmp(program_invocation_name, buf) != 0)
+		return 1;
+
+	dirsep = strrchr(buf, '/');
+	if (!dirsep || dirsep[1] == '\0')
+		return 1;
+
+	if (strcmp(program_invocation_short_name, dirsep + 1) != 0)
+		return 1;
+
+	return 0;
+}
+
 int run_startup(int min, int max)
 {
 	int test;
@@ -716,6 +747,7 @@ int run_startup(int min, int max)
 #ifdef NOLIBC
 	test_auxv = _auxv;
 #endif
+	bool proc = access("/proc", R_OK) == 0;
 
 	for (test = min; test >= 0 && test <= max; test++) {
 		int llen = 0; /* line length */
@@ -741,6 +773,7 @@ int run_startup(int min, int max)
 		CASE_TEST(constructor);      EXPECT_EQ(is_nolibc, constructor_test_value, 0x3); break;
 		CASE_TEST(linkage_errno);    EXPECT_PTREQ(1, linkage_test_errno_addr(), &errno); break;
 		CASE_TEST(linkage_constr);   EXPECT_EQ(1, linkage_test_constructor_test_value, 0x3); break;
+		CASE_TEST(prog_name);        EXPECT_ZR(proc, test_program_invocation_name()); break;
 		case __LINE__:
 			return ret; /* must be last */
 		/* note: do not set any defaults so as to permit holes above */

-- 
2.53.0

Re: [PATCH v3 1/2] tools/nolibc: add support for program_invocation_{,short_}name
Posted by kernel test robot 2 weeks, 6 days ago
Hi Thomas,

kernel test robot noticed the following build errors:

[auto build test ERROR on 745dadd6d3d984feafb96f27b60d74b29ade4957]

url:    https://github.com/intel-lab-lkp/linux/commits/Thomas-Wei-schuh/tools-nolibc-add-support-for-program_invocation_-short_-name/20260317-060704
base:   745dadd6d3d984feafb96f27b60d74b29ade4957
patch link:    https://lore.kernel.org/r/20260316-nolibc-err-h-v3-1-6ef80c051ab7%40weissschuh.net
patch subject: [PATCH v3 1/2] tools/nolibc: add support for program_invocation_{,short_}name
config: s390-allnoconfig-bpf (https://download.01.org/0day-ci/archive/20260317/202603171011.58aT1Db0-lkp@intel.com/config)
compiler: s390x-linux-gnu-gcc (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260317/202603171011.58aT1Db0-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603171011.58aT1Db0-lkp@intel.com/

All errors (new ones prefixed by >>):

   nolibc-test.c: In function 'run_startup':
>> nolibc-test.c:750:9: error: unknown type name 'bool'
     750 |         bool proc = access("/proc", R_OK) == 0;
         |         ^~~~
   nolibc-test.c:49:1: note: 'bool' is defined in header '<stdbool.h>'; this is probably fixable by adding '#include <stdbool.h>'
      48 | #include "nolibc-test-linkage.h"
     +++ |+#include <stdbool.h>
      49 | 

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki