lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Sat, 21 Dec 2013 23:49:25 +0800
From:	Hui Zhu <teawater@...il.com>
To:	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
CC:	acme@...hat.com, bp@...e.de, gthelen@...gle.com,
	rui.zhang@...el.com, jacob.jun.pan@...ux.intel.com,
	albcamus@...il.com
Subject: [PATCH 1/2] tool and script help GDB load Linux kernel modules (tool)

getmod a application of KGTP (https://kgtp.googlecode.com).

It can get Linux Kernel modules info from sysfs and output them as GDB
command add-symbol-file format.  Then you can call "source output_file_name"
inside GDB to let it load all the debug info of Linux Kernel modules.
It will help debug Linux Kernel modules with GDB with gdbstub such as
KGTP, KGDB, QEMU.

It was written by C and built with -static make it friendly to the embedded
system.
Following part is the help info of getmod:
Usage: ./getmod [option]
   -s dir    Add dir to module search directory list.
             This options can use more than once.
   -S        Add /lib/modules/3.2.0-57-generic/kernel to module search directory list.
   -r dir    Add dir to replace the directory.
             This options can use more than once.
   -n        No search the directory of the module
             file directory.
   -h        Display this information.

Signed-off-by: Hui Zhu <teawater@...il.com>
---
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -16,6 +16,7 @@ help:
  	@echo '  vm         - misc vm tools'
  	@echo '  x86_energy_perf_policy - Intel energy policy tool'
  	@echo '  tmon       - thermal monitoring and tuning tool'
+	@echo '  getmod     - Output LKM info in GDB add-symbol-file format.'
  	@echo ''
  	@echo 'You can do:'
  	@echo ' $$ make -C tools/ <tool>_install'
@@ -36,7 +37,7 @@ help:
  cpupower: FORCE
  	$(call descend,power/$@)
  
-cgroup firewire guest usb virtio vm net: FORCE
+cgroup firewire guest usb virtio vm net getmod: FORCE
  	$(call descend,$@)
  
  liblk: FORCE
@@ -77,7 +78,7 @@ install: cgroup_install cpupower_install
  cpupower_clean:
  	$(call descend,power/cpupower,clean)
  
-cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
+cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean getmod_clean:
  	$(call descend,$(@:_clean=),clean)
  
  liblk_clean:
@@ -97,6 +98,7 @@ tmon_clean:
  
  clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \
  		selftests_clean turbostat_clean usb_clean virtio_clean \
-		vm_clean net_clean x86_energy_perf_policy_clean tmon_clean
+		vm_clean net_clean x86_energy_perf_policy_clean tmon_clean \
+		getmod_clean
  
  .PHONY: FORCE
--- /dev/null
+++ b/tools/getmod/Makefile
@@ -0,0 +1,11 @@
+prefix = /usr
+
+all : getmod
+
+getmod : CFLAGS = -Wall -O2 -static
+
+clean :
+	rm -rf getmod
+
+install :
+	install getmod $(prefix)/sbin/
--- /dev/null
+++ b/tools/getmod/getmod.c
@@ -0,0 +1,407 @@
+/*
+ * Output Linux Kernel modules info in GDB add-symbol-file format.
+ *
+ * Copyright(C) KGTP team (https://kgtp.googlecode.com), 2011-2013
+ * Licensed under the GNU General Public License, version 2.0 (GPLv2)
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/utsname.h>
+#include <dirent.h>
+
+#define MOD_DIR		"/lib/modules"
+#define PROC_MOD	"/proc/modules"
+#define SYS_MOD		"/sys/module"
+
+#define SDIR_MAX	16
+
+int	sdir_number = 0;
+char	*sdir[SDIR_MAX];
+
+int	rdir_number = 0;
+int	rdir_current = 0;
+char	*rdir[SDIR_MAX];
+
+char	got_dir[512];
+
+int	no_search_mod = 0;
+
+int
+search_mod_1(char *dir, char *file)
+{
+	DIR		*dp;
+	struct dirent	*ptr;
+	int		ret = 0;
+
+	dp = opendir(dir);
+	if (!dp) {
+		fprintf(stderr, "#Cannot open %s: %s.\n", dir,
+			strerror(errno));
+		ret = -1;
+		goto out;
+	}
+	while ((ptr = readdir(dp)) != NULL) {
+		char	cdir[512];
+
+		if (ptr->d_type == DT_DIR) {
+			if (strcmp(ptr->d_name, ".") == 0)
+				continue;
+			if (strcmp(ptr->d_name, "..") == 0)
+				continue;
+			snprintf(cdir, 512, "%s/%s", dir, ptr->d_name);
+			if (search_mod_1(cdir, file)) {
+				ret = 1;
+				break;
+			}
+		} else {
+			int	i;
+
+			snprintf(cdir, 512, "%s", ptr->d_name);
+			for (i = 0; i < strlen(cdir); i++) {
+				if (cdir[i] == '_')
+					cdir[i] = '-';
+			}
+			if (strcmp(cdir, file) == 0) {
+				snprintf(got_dir, 512, "%s/%s", dir,
+					 ptr->d_name);
+				ret = 1;
+				break;
+			}
+		}
+	}
+	closedir(dp);
+
+out:
+	return ret;
+}
+
+int
+search_mod(char *dir, char *file)
+{
+	int	ret;
+	char	tmp_dir[512];
+
+	ret = search_mod_1(dir, file);
+	if (ret <= 0)
+		return ret;
+
+	if (rdir_number == 0)
+		return 1;
+
+	if (rdir_current >= rdir_number)
+		rdir_current--;
+
+	strcpy(tmp_dir, got_dir);
+	snprintf(got_dir, 512, "%s%s", rdir[rdir_current],
+		 tmp_dir + strlen(dir));
+
+	rdir_current++;
+	return 1;
+}
+
+void
+print_mod(char *name, char *addr)
+{
+	int		i;
+	char		mod_dir[256];
+	struct stat	sbuf;
+	char		file[64];
+	DIR		*dp;
+	struct dirent	*ptr;
+
+	snprintf(file, 64, "%s.ko", name);
+
+	if (no_search_mod)
+		printf("add-symbol-file %s %s", file, addr);
+	else {
+		for (i = 0; i < strlen(file); i++) {
+			if (file[i] == '_')
+				file[i] = '-';
+		}
+		for (i = 0; i < sdir_number; i++) {
+			int	ret;
+
+			if (sdir[i] == NULL)
+				continue;
+			ret = search_mod(sdir[i], file);
+			if (ret < 0)
+				sdir[i] = NULL;
+			if (ret > 0)
+				break;
+		}
+		if (i >= sdir_number) {
+			for (i = 0; i < sdir_number; i++) {
+				if (sdir[i])
+					break;
+			}
+			if (i >= sdir_number) {
+				no_search_mod = 1;
+				fprintf(stderr,
+					"#Cannot open any module search directories.  Auto open -n.\n");
+			} else
+				fprintf(stderr,
+					"#Cannot find file %s in the module search directories.  Just output the command with filename.\n",
+					file);
+			printf("#add-symbol-file %s %s", file, addr);
+		} else
+			printf("add-symbol-file %s %s", got_dir, addr);
+	}
+
+	snprintf(mod_dir, 256, "%s/%s/sections", SYS_MOD, name);
+	/* Check mod_dir.  */
+	if (stat(mod_dir, &sbuf) || !S_ISDIR(sbuf.st_mode)) {
+		fprintf(stderr, "%s is not a right directory.\n", mod_dir);
+		exit(-1);
+	}
+
+	dp = opendir(mod_dir);
+	if (!dp) {
+		fprintf(stderr, "Cannot open %s: %s.\n", mod_dir,
+			strerror(errno));
+		exit(-errno);
+	}
+	while ((ptr = readdir(dp)) != NULL) {
+		if (ptr->d_type == DT_REG) {
+			char	section_file_name[512];
+			FILE	*fp;
+			char	line[256];
+			size_t	size;
+
+			if (strcmp(ptr->d_name, ".text") == 0
+			    || strcmp(ptr->d_name, ".symtab") == 0
+			    || strcmp(ptr->d_name, ".strtab") == 0)
+				continue;
+
+			snprintf(section_file_name, 512, "%s/%s", mod_dir,
+				 ptr->d_name);
+			fp = fopen(section_file_name, "r");
+			if (!fp) {
+				perror(section_file_name);
+				exit(-errno);
+			}
+			if (fgets(line, 256, fp) == NULL) {
+				perror(section_file_name);
+				exit(-errno);
+			}
+			fclose(fp);
+			size = strlen(line);
+			if (size == 0) {
+				fprintf(stderr, "format of %s is not right.\n",
+					section_file_name);
+				exit(-errno);
+			}
+			if (line[size - 1] == '\n')
+				line[size - 1] = '\0';
+			printf(" -s %s %s", ptr->d_name, line);
+		}
+	}
+	closedir(dp);
+
+	printf("\n");
+}
+
+int
+check_sdir(char *dir)
+{
+	struct stat	sbuf;
+
+	if (stat(dir, &sbuf) || !S_ISDIR(sbuf.st_mode)) {
+		fprintf(stderr,
+			"#%s is not a right directory.  Ignore it.\n",
+			dir);
+		return 0;
+	}
+
+	return 1;
+}
+
+void
+add_sdir(char *dir)
+{
+	if (sdir_number < SDIR_MAX) {
+		if (check_sdir(dir)) {
+			sdir[sdir_number] = dir;
+			sdir_number++;
+		}
+	} else {
+		fprintf(stderr, "Set too much module search directory.");
+		exit(-1);
+	}
+}
+
+void
+add_rdir(char *dir)
+{
+	if (rdir_number < SDIR_MAX) {
+		rdir[rdir_number] = dir;
+		rdir_number++;
+	} else {
+		fprintf(stderr, "Set too much module search directory.");
+		exit(-1);
+	}
+}
+
+char *
+get_default_sdir(void)
+{
+	static int	need_init = 1;
+	static char	dir[512];
+
+	if (need_init) {
+		struct utsname	ubuf;
+
+		if (uname(&ubuf)) {
+			fprintf(stderr, "Fail to get kernel version.");
+			exit(-errno);
+		}
+		snprintf(dir, 512, "%s/%s/kernel", MOD_DIR, ubuf.release);
+	}
+
+	return dir;
+}
+
+void
+print_usage(char *arg)
+{
+	printf("Output LKM info in GDB add-symbol-file format.\n"
+	       "Usage: %s [option]\n\n"
+
+	       "  -s dir    Add dir to module search directory list.\n"
+	       "            This options can use more than once.\n\n"
+
+	       "  -S        Add %s to module search directory list.\n\n"
+
+	       "  -r dir    Add dir to replace the directory.\n"
+	       "            This options can use more than once.\n\n"
+
+	       "  -n        No search the directory of the module\n"
+	       "            file directory.\n\n"
+
+	       "  -h        Display this information.\n",
+	       arg, get_default_sdir());
+
+	exit(0);
+}
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+	struct stat	sbuf;
+	FILE		*fp;
+	char		line[4096];
+	int		c;
+	int		default_sdir_isset = 0;
+
+	if (geteuid() != 0) {
+		fprintf(stderr,
+			"Only root can get the right address of modules.\n");
+		exit(-1);
+	}
+
+	while ((c = getopt(argc, argv, "s:Sr:nh")) != -1) {
+		switch (c) {
+		case 's':
+			add_sdir(optarg);
+			break;
+		case 'S':
+			if (!default_sdir_isset)
+				add_sdir(get_default_sdir());
+			break;
+		case 'r':
+			add_rdir(optarg);
+			break;
+		case 'n':
+			no_search_mod = 1;
+			break;
+		case 'h':
+		default:
+			print_usage(argv[0]);
+			break;
+		}
+	}
+
+	if (!no_search_mod && sdir_number == 0)
+		add_sdir(get_default_sdir());
+	if (!no_search_mod && sdir_number == 0) {
+		no_search_mod = 1;
+		fprintf(stderr,
+			"#Cannot open any module search directories.  Auto open -n.\n");
+	}
+
+	/* Check PROC_MOD.  */
+	if (stat(PROC_MOD, &sbuf) || !S_ISREG(sbuf.st_mode)) {
+		fprintf(stderr, "%s is not right.\n", PROC_MOD);
+		exit(-1);
+	}
+
+	/* Get module name and address from PROC_MOD.  */
+	fp = fopen(PROC_MOD, "r");
+	if (!fp) {
+		perror(PROC_MOD);
+		exit(-errno);
+	}
+	while (fgets(line, 4096, fp)) {
+		int	i;
+		size_t	size = strlen(line);
+		int	is_not_digit = 0;
+
+		if (line[size - 1] != '\n') {
+			fprintf(stderr,
+				"line:%s is too big to parse by getmod.\n",
+				line);
+			exit(-1);
+		}
+
+		/* This part get the name.  */
+		for (i = 0; i < size; i++) {
+			if (line[i] == ' ') {
+				line[i] = '\0';
+				break;
+			}
+		}
+		/* Following part will get the addr.  */
+		if (i == size) {
+			fprintf(stderr,
+				"The format of \"%s\" is not right.\n", line);
+			exit(-1);
+		}
+		if (line[size - 1] == '\n')
+			line[size - 1] = '\0';
+		for (i = size - 2; i >= 0; i--) {
+			if (line[i] == ' ') {
+				if (is_not_digit) {
+					line[i] = '\0';
+					is_not_digit = 0;
+				} else
+					break;
+			} else {
+				if (line[i] != 'x' && line[i] != 'X'
+				    && (line[i] < '0' || line[i] > '9')
+				    && (line[i] < 'a' || line[i] > 'f')
+				    && (line[i] < 'A' || line[i] > 'F'))
+					is_not_digit = 1;
+			}
+		}
+		if (i < 0) {
+			fprintf(stderr, "The format of \"%s\" is not right.\n",
+				line);
+			exit(-1);
+		}
+		print_mod(line, line + i + 1);
+	}
+	if (ferror(fp)) {
+		perror(PROC_MOD);
+		exit(-errno);
+	}
+	fclose(fp);
+
+	return 0;
+}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists