Index: abi/include/abi/sysinfo.h
===================================================================
--- abi/include/abi/sysinfo.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ abi/include/abi/sysinfo.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -37,4 +37,5 @@
 #define _ABI_SYSINFO_H_
 
+#include <_bits/size_t.h>
 #include <stdbool.h>
 #include <abi/proc/task.h>
Index: kernel/generic/include/debug/line.h
===================================================================
--- kernel/generic/include/debug/line.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/include/debug/line.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -33,4 +33,5 @@
 #include <stddef.h>
 #include <stdint.h>
+#include <debug/sections.h>
 
 struct debug_line_program_header {
@@ -103,5 +104,5 @@
 }
 
-extern bool debug_line_get_address_info(uintptr_t addr, int op_index, const char **file, const char **dir, int *line, int *col);
+extern bool debug_line_get_address_info(debug_sections_t *scs, uintptr_t addr, int op_index, const char **file, const char **dir, int *line, int *col);
 
 #endif /* DWARFS_LINE_H_ */
Index: kernel/generic/include/debug/sections.h
===================================================================
--- kernel/generic/include/debug/sections.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/include/debug/sections.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -33,36 +33,42 @@
 #include <stddef.h>
 
-extern const void *debug_aranges;
-extern size_t debug_aranges_size;
+typedef struct {
+	const void *debug_aranges;
+	size_t debug_aranges_size;
 
-extern const void *debug_info;
-extern size_t debug_info_size;
+	const void *debug_info;
+	size_t debug_info_size;
 
-extern const void *debug_abbrev;
-extern size_t debug_abbrev_size;
+	const void *debug_abbrev;
+	size_t debug_abbrev_size;
 
-extern const void *debug_line;
-extern size_t debug_line_size;
+	const void *debug_line;
+	size_t debug_line_size;
 
-extern const char *debug_str;
-extern size_t debug_str_size;
+	const char *debug_str;
+	size_t debug_str_size;
 
-extern const char *debug_line_str;
-extern size_t debug_line_str_size;
+	const char *debug_line_str;
+	size_t debug_line_str_size;
 
-extern const void *debug_rnglists;
-extern size_t debug_rnglists_size;
+	const void *debug_rnglists;
+	size_t debug_rnglists_size;
 
-extern const void *eh_frame_hdr;
-extern size_t eh_frame_hdr_size;
+	const void *eh_frame_hdr;
+	size_t eh_frame_hdr_size;
 
-extern const void *eh_frame;
-extern size_t eh_frame_size;
+	const void *eh_frame;
+	size_t eh_frame_size;
 
-extern const elf_symbol_t *symtab;
-extern size_t symtab_size;
+	const elf_symbol_t *symtab;
+	size_t symtab_size;
 
-extern const char *strtab;
-extern size_t strtab_size;
+	const char *strtab;
+	size_t strtab_size;
+} debug_sections_t;
+
+extern debug_sections_t kernel_sections;
+
+debug_sections_t get_debug_sections(const void *elf, size_t elf_size);
 
 #endif /* DEBUG_SECTIONS_H_ */
Index: kernel/generic/include/proc/program.h
===================================================================
--- kernel/generic/include/proc/program.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/include/proc/program.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -56,5 +56,5 @@
 
 extern errno_t program_create(as_t *, uspace_addr_t, char *, program_t *);
-extern errno_t program_create_from_image(void *, char *, program_t *);
+extern errno_t program_create_from_image(void *, size_t, char *, program_t *);
 extern errno_t program_create_loader(program_t *, char *);
 extern void program_ready(program_t *);
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/include/proc/task.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -36,26 +36,27 @@
 #define KERN_TASK_H_
 
-#include <cpu.h>
-#include <ipc/ipc.h>
-#include <ipc/event.h>
-#include <ipc/kbox.h>
-#include <synch/spinlock.h>
-#include <synch/mutex.h>
+#include <abi/proc/task.h>
+#include <abi/sysinfo.h>
 #include <adt/list.h>
 #include <adt/odict.h>
-#include <security/perm.h>
+#include <arch/context.h>
+#include <arch/cpu.h>
+#include <arch/fpu_context.h>
 #include <arch/proc/task.h>
 #include <arch/proc/thread.h>
-#include <arch/context.h>
-#include <arch/fpu_context.h>
-#include <arch/cpu.h>
+#include <arch.h>
+#include <cap/cap.h>
+#include <cpu.h>
+#include <debug/sections.h>
+#include <ipc/event.h>
+#include <ipc/ipc.h>
+#include <ipc/kbox.h>
+#include <mm/as.h>
 #include <mm/tlb.h>
 #include <proc/scheduler.h>
+#include <security/perm.h>
+#include <synch/mutex.h>
+#include <synch/spinlock.h>
 #include <udebug/udebug.h>
-#include <mm/as.h>
-#include <abi/proc/task.h>
-#include <abi/sysinfo.h>
-#include <arch.h>
-#include <cap/cap.h>
 
 #define TASK                 CURRENT->task
@@ -131,4 +132,6 @@
 	uint64_t ucycles;
 	uint64_t kcycles;
+
+	debug_sections_t *debug_sections;
 } task_t;
 
Index: kernel/generic/include/symtab.h
===================================================================
--- kernel/generic/include/symtab.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/include/symtab.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -36,5 +36,7 @@
 #define KERN_SYMTAB_H_
 
+#include <stdbool.h>
 #include <typedefs.h>
+#include <debug/sections.h>
 
 extern void symtab_print_search(const char *);
@@ -42,5 +44,5 @@
 extern const char *symtab_fmt_name_lookup(uintptr_t);
 extern errno_t symtab_addr_lookup(const char *, uintptr_t *);
-extern const char *symtab_name_lookup(uintptr_t, uintptr_t *);
+extern const char *symtab_name_lookup(uintptr_t, uintptr_t *, debug_sections_t *);
 
 #endif
Index: kernel/generic/src/debug/line.c
===================================================================
--- kernel/generic/src/debug/line.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/debug/line.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -297,5 +297,5 @@
 }
 
-static void debug_line_program_header_parse(const uint8_t *data, const uint8_t *data_end, struct debug_line_program_header *hdr)
+static void debug_line_program_header_parse(debug_sections_t *scs, const uint8_t *data, const uint8_t *data_end, struct debug_line_program_header *hdr)
 {
 	const uint8_t *unit_start = data;
@@ -378,5 +378,5 @@
 		hdr->v5.directories_end = data;
 
-		print_formatted_list("directories", hdr->v5.directories, hdr->v5.directories_end,
+		print_formatted_list(scs, "directories", hdr->v5.directories, hdr->v5.directories_end,
 		    hdr->v5.directory_entry_format, hdr->v5.directory_entry_format_end, width);
 
@@ -397,5 +397,5 @@
 		hdr->v5.file_names_end = data;
 
-		print_formatted_list("file_names", hdr->v5.file_names, hdr->v5.file_names_end,
+		print_formatted_list(scs, "file_names", hdr->v5.file_names, hdr->v5.file_names_end,
 		    hdr->v5.file_name_entry_format, hdr->v5.file_name_entry_format_end, width);
 	}
@@ -463,5 +463,5 @@
 }
 
-static const char *get_file_name_v5(struct debug_line_program_header *hdr, int file, int *dir)
+static const char *get_file_name_v5(debug_sections_t *scs, struct debug_line_program_header *hdr, int file, int *dir)
 {
 	// DWARF5 has dynamic layout for file information, which is why
@@ -493,6 +493,6 @@
 				if (form == DW_FORM_line_strp) {
 					uint64_t offset = read_uint(&fns, fns_end, hdr->width);
-					if (offset < debug_line_str_size) {
-						filename = debug_line_str + offset;
+					if (offset < scs->debug_line_str_size) {
+						filename = scs->debug_line_str + offset;
 					}
 					continue;
@@ -527,5 +527,5 @@
 }
 
-static const char *get_file_name(struct debug_line_program_header *hdr, int file, int *dir)
+static const char *get_file_name(debug_sections_t *scs, struct debug_line_program_header *hdr, int file, int *dir)
 {
 	switch (hdr->version) {
@@ -534,5 +534,5 @@
 		return get_file_name_v3(hdr, file, dir);
 	case 5:
-		return get_file_name_v5(hdr, file, dir);
+		return get_file_name_v5(scs, hdr, file, dir);
 	default:
 		return NULL;
@@ -558,5 +558,5 @@
 }
 
-static const char *get_dir_name_v5(struct debug_line_program_header *hdr, int dir)
+static const char *get_dir_name_v5(debug_sections_t *scs, struct debug_line_program_header *hdr, int dir)
 {
 	// TODO: basically a copypaste of get_file_name(). Try to deduplicate it.
@@ -587,6 +587,6 @@
 				if (form == DW_FORM_line_strp) {
 					uint64_t offset = read_uint(&fns, fns_end, hdr->width);
-					if (offset < debug_line_str_size) {
-						filename = debug_line_str + offset;
+					if (offset < scs->debug_line_str_size) {
+						filename = scs->debug_line_str + offset;
 					}
 					continue;
@@ -604,5 +604,5 @@
 }
 
-static const char *get_dir_name(struct debug_line_program_header *hdr, int dir)
+static const char *get_dir_name(debug_sections_t *scs, struct debug_line_program_header *hdr, int dir)
 {
 	switch (hdr->version) {
@@ -611,5 +611,5 @@
 		return get_dir_name_v3(hdr, dir);
 	case 5:
-		return get_dir_name_v5(hdr, dir);
+		return get_dir_name_v5(scs, hdr, dir);
 	default:
 		return NULL;
@@ -617,5 +617,5 @@
 }
 
-static const uint8_t *find_line_program(uintptr_t addr)
+static const uint8_t *find_line_program(debug_sections_t *scs, uintptr_t addr)
 {
 	// TODO: use .debug_aranges to find the data quickly
@@ -625,6 +625,6 @@
 	const uint8_t *closest_prog = NULL;
 
-	const uint8_t *debug_line_ptr = debug_line;
-	const uint8_t *const debug_line_end = debug_line + debug_line_size;
+	const uint8_t *debug_line_ptr = scs->debug_line;
+	const uint8_t *const debug_line_end = scs->debug_line + scs->debug_line_size;
 
 	while (debug_line_ptr < debug_line_end) {
@@ -633,5 +633,5 @@
 		// Parse header
 		struct debug_line_program_header hdr = { };
-		debug_line_program_header_parse(prog, debug_line_end, &hdr);
+		debug_line_program_header_parse(scs, prog, debug_line_end, &hdr);
 		assert(hdr.unit_end > debug_line_ptr);
 		assert(hdr.unit_end <= debug_line_end);
@@ -678,23 +678,27 @@
 		debug_line_program_advance(&lp);
 
-		if (!lp.truncated) {
-			// We check for the last address before addr, because addr
-			// is a return address and we want the call instruction.
-			if (lp.address >= addr && lp.op_advance >= op_index) {
-				if (!first) {
-					*file = last_file;
-					*line = last_line;
-					*column = last_column;
-					return true;
-				}
-
+		if (lp.truncated)
+			continue;
+
+		/*
+		 * Return previous entry when we pass the target address, because
+		 * the address may not be aligned perfectly on instruction boundary.
+		 */
+		if (lp.address > addr || (lp.address == addr && lp.op_advance > op_index)) {
+			if (first) {
 				// First address is already too large, skip to the next sequence.
 				debug_line_program_skip_to_sequence_end(&lp);
-			}
-
-			last_file = lp.file;
-			last_line = lp.line;
-			last_column = lp.column;
-		}
+				continue;
+			}
+
+			*file = last_file;
+			*line = last_line;
+			*column = last_column;
+			return true;
+		}
+
+		last_file = lp.file;
+		last_line = lp.line;
+		last_column = lp.column;
 	}
 
@@ -702,15 +706,15 @@
 }
 
-bool debug_line_get_address_info(uintptr_t addr, int op_index, const char **file_name, const char **dir_name, int *line, int *column)
-{
-	const uint8_t *data = find_line_program(addr);
+bool debug_line_get_address_info(debug_sections_t *scs, uintptr_t addr, int op_index, const char **file_name, const char **dir_name, int *line, int *column)
+{
+	const uint8_t *data = find_line_program(scs, addr);
 	if (data == NULL) {
 		return false;
 	}
 
-	const uint8_t *const debug_line_end = debug_line + debug_line_size;
+	const uint8_t *const debug_line_end = scs->debug_line + scs->debug_line_size;
 
 	struct debug_line_program_header hdr = { };
-	debug_line_program_header_parse(data, debug_line_end, &hdr);
+	debug_line_program_header_parse(scs, data, debug_line_end, &hdr);
 	assert(hdr.unit_end > data);
 	assert(hdr.unit_end <= debug_line_end);
@@ -727,8 +731,8 @@
 
 	if (file >= 0)
-		*file_name = get_file_name(&hdr, file, &dir);
+		*file_name = get_file_name(scs, &hdr, file, &dir);
 
 	if (dir >= 0)
-		*dir_name = get_dir_name(&hdr, dir);
+		*dir_name = get_dir_name(scs, &hdr, dir);
 
 	return true;
Index: kernel/generic/src/debug/sections.c
===================================================================
--- kernel/generic/src/debug/sections.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/debug/sections.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -29,41 +29,12 @@
 #include <debug/sections.h>
 #include <debug/register.h>
+#include <debug.h>
 
 #include <stdio.h>
 #include <str.h>
 
-const void *debug_aranges = NULL;
-size_t debug_aranges_size = 0;
+#define DEBUGF dummy_printf
 
-const void *debug_info = NULL;
-size_t debug_info_size = 0;
-
-const void *debug_abbrev = NULL;
-size_t debug_abbrev_size = 0;
-
-const void *debug_line = NULL;
-size_t debug_line_size = 0;
-
-const char *debug_str = NULL;
-size_t debug_str_size = 0;
-
-const char *debug_line_str = NULL;
-size_t debug_line_str_size = 0;
-
-const void *debug_rnglists = NULL;
-size_t debug_rnglists_size = 0;
-
-// TODO: get this from the program image
-const void *eh_frame_hdr = NULL;
-size_t eh_frame_hdr_size = 0;
-
-const void *eh_frame = NULL;
-size_t eh_frame_size = 0;
-
-const elf_symbol_t *symtab = NULL;
-size_t symtab_size = 0;
-
-const char *strtab = NULL;
-size_t strtab_size = 0;
+debug_sections_t kernel_sections;
 
 struct section_manifest {
@@ -73,27 +44,34 @@
 };
 
-#define section(name) { "." #name, (const void **)&name, &name##_size }
+static void _check_string_section(const char *section, size_t *section_size)
+{
+	while (*section_size > 0 && section[*section_size - 1] != 0) {
+		(*section_size)--;
+	}
+}
 
-static const struct section_manifest manifest[] = {
-	section(debug_aranges),
-	section(debug_info),
-	section(debug_abbrev),
-	section(debug_line),
-	section(debug_str),
-	section(debug_line_str),
-	section(debug_rnglists),
-	section(eh_frame_hdr),
-	section(eh_frame),
-	section(symtab),
-	section(strtab),
-};
+debug_sections_t get_debug_sections(const void *elf, size_t elf_size)
+{
+	debug_sections_t out = { };
 
-#undef section
+#define section(name) { "." #name, (const void **)&out.name, &out.name##_size }
 
-static const size_t manifest_len = sizeof(manifest) / sizeof(struct section_manifest);
+	const struct section_manifest manifest[] = {
+		section(debug_aranges),
+		section(debug_info),
+		section(debug_abbrev),
+		section(debug_line),
+		section(debug_str),
+		section(debug_line_str),
+		section(debug_rnglists),
+		section(eh_frame_hdr),
+		section(eh_frame),
+		section(symtab),
+		section(strtab),
+	};
 
-void register_debug_data(const void *data, size_t data_size)
-{
-	const void *data_end = data + data_size;
+	const size_t manifest_len = sizeof(manifest) / sizeof(struct section_manifest);
+
+	const void *data_end = elf + elf_size;
 
 	/*
@@ -103,59 +81,57 @@
 	 */
 
-	if (data_size < sizeof(elf_header_t)) {
+	if (elf_size < sizeof(elf_header_t)) {
 		printf("bad debug data: too short\n");
-		return;
+		return out;
 	}
 
-	if (((uintptr_t) data) % 8 != 0) {
+	if (((uintptr_t) elf) % 8 != 0) {
 		printf("bad debug data: unaligned input\n");
-		return;
+		return out;
 	}
 
-	const elf_header_t *hdr = data;
+	const elf_header_t *hdr = elf;
 
 	if (hdr->e_ident[0] != ELFMAG0 || hdr->e_ident[1] != ELFMAG1 ||
 	    hdr->e_ident[2] != ELFMAG2 || hdr->e_ident[3] != ELFMAG3) {
 		printf("bad debug data: wrong ELF magic bytes\n");
-		return;
+		return out;
 	}
 
 	if (hdr->e_shentsize != sizeof(elf_section_header_t)) {
 		printf("bad debug data: wrong e_shentsize\n");
-		return;
+		return out;
 	}
 
 	/* Get section header table. */
-	const elf_section_header_t *shdr = data + hdr->e_shoff;
+	const elf_section_header_t *shdr = elf + hdr->e_shoff;
 	size_t shdr_len = hdr->e_shnum;
 
 	if ((void *) &shdr[shdr_len] > data_end) {
 		printf("bad debug data: truncated section header table\n");
-		return;
+		return out;
 	}
 
 	if (hdr->e_shstrndx >= shdr_len) {
 		printf("bad debug data: string table index out of range\n");
-		return;
+		return out;
 	}
 
 	/* Get data on section name string table. */
 	const elf_section_header_t *shstr = &shdr[hdr->e_shstrndx];
-	const char *shstrtab = data + shstr->sh_offset;
+	const char *shstrtab = elf + shstr->sh_offset;
 	size_t shstrtab_size = shstr->sh_size;
 
 	if ((void *) shstrtab + shstrtab_size > data_end) {
 		printf("bad debug data: truncated string table\n");
-		return;
+		return out;
 	}
 
 	/* Check NUL-terminator. */
-	while (shstrtab_size > 0 && shstrtab[shstrtab_size - 1] != 0) {
-		shstrtab_size--;
-	}
+	_check_string_section(shstrtab, &shstrtab_size);
 
 	if (shstrtab_size == 0) {
 		printf("bad debug data: empty or non-null-terminated string table\n");
-		return;
+		return out;
 	}
 
@@ -167,5 +143,5 @@
 		if (shdr[i].sh_name >= shstrtab_size) {
 			printf("bad debug data: string table index out of range\n");
-			return;
+			continue;
 		}
 
@@ -174,7 +150,7 @@
 		size_t size = shdr[i].sh_size;
 
-		printf("section '%s': offset %zd (%zd bytes)\n", name, offset, size);
+		DEBUGF("section '%s': offset %zd (%zd bytes)\n", name, offset, size);
 
-		if (data + offset + size > data_end) {
+		if (elf + offset + size > data_end) {
 			printf("bad debug data: truncated section %s\n", name);
 			continue;
@@ -183,5 +159,5 @@
 		for (size_t i = 0; i < manifest_len; i++) {
 			if (str_cmp(manifest[i].name, name) == 0) {
-				*manifest[i].address_field = data + offset;
+				*manifest[i].address_field = elf + offset;
 				*manifest[i].size_field = size;
 				break;
@@ -191,14 +167,13 @@
 
 	/* Check NUL-terminator in .strtab, .debug_str and .debug_line_str */
-	while (strtab_size > 0 && strtab[strtab_size - 1] != 0) {
-		strtab_size--;
-	}
+	_check_string_section(out.strtab, &out.strtab_size);
+	_check_string_section(out.debug_str, &out.debug_str_size);
+	_check_string_section(out.debug_line_str, &out.debug_line_str_size);
 
-	while (debug_str_size > 0 && debug_str[debug_str_size - 1] != 0) {
-		debug_str_size--;
-	}
+	return out;
+}
 
-	while (debug_line_str_size > 0 && debug_str[debug_line_str_size - 1] != 0) {
-		debug_line_str_size--;
-	}
+void register_debug_data(const void *elf, size_t elf_size)
+{
+	kernel_sections = get_debug_sections(elf, elf_size);
 }
Index: kernel/generic/src/debug/stacktrace.c
===================================================================
--- kernel/generic/src/debug/stacktrace.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/debug/stacktrace.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -60,6 +60,12 @@
 		int column = 0;
 
+		/*
+		 * If this isn't the first frame, move pc back by one byte to read the
+		 * position of the call instruction, not the return address.
+		 */
+		pc = cnt == 1 ? ctx->pc : ctx->pc - 1;
+
 		if (ops->symbol_resolve &&
-		    ops->symbol_resolve(ctx->pc, 0, &symbol, &symbol_addr, &file_name, &dir_name, &line, &column)) {
+		    ops->symbol_resolve(pc, 0, &symbol, &symbol_addr, &file_name, &dir_name, &line, &column)) {
 
 			if (symbol == NULL)
@@ -130,7 +136,24 @@
 {
 	*symbol_addr = 0;
-	*symbol = symtab_name_lookup(addr, symbol_addr);
+	*symbol = symtab_name_lookup(addr, symbol_addr, &kernel_sections);
 
-	return debug_line_get_address_info(addr, op_index, filename, dirname, line, column) || *symbol_addr != 0;
+	return debug_line_get_address_info(&kernel_sections, addr, op_index, filename, dirname, line, column) || *symbol_addr != 0;
+}
+
+static bool
+resolve_uspace_address(uintptr_t addr, int op_index,
+    const char **symbol, uintptr_t *symbol_addr,
+    const char **filename, const char **dirname,
+    int *line, int *column)
+{
+	if (TASK->debug_sections == NULL)
+		return false;
+
+	debug_sections_t *scs = TASK->debug_sections;
+
+	*symbol_addr = 0;
+	*symbol = symtab_name_lookup(addr, symbol_addr, scs);
+
+	return debug_line_get_address_info(scs, addr, op_index, filename, dirname, line, column) || *symbol_addr != 0;
 }
 
@@ -146,5 +169,5 @@
 	.frame_pointer_prev = uspace_frame_pointer_prev,
 	.return_address_get = uspace_return_address_get,
-	.symbol_resolve = NULL
+	.symbol_resolve = resolve_uspace_address,
 };
 
Index: kernel/generic/src/debug/symtab.c
===================================================================
--- kernel/generic/src/debug/symtab.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/debug/symtab.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -36,36 +36,33 @@
  */
 
+#include <abi/elf.h>
+#include <byteorder.h>
+#include <console/prompt.h>
+#include <debug/sections.h>
+#include <errno.h>
+#include <proc/task.h>
+#include <stdio.h>
+#include <str.h>
 #include <symtab.h>
-#include <byteorder.h>
-#include <str.h>
-#include <stdio.h>
 #include <typedefs.h>
-#include <errno.h>
-#include <console/prompt.h>
-
-#include <abi/elf.h>
-#include <debug/sections.h>
-
-static inline size_t symtab_len()
-{
-	return symtab_size / sizeof(elf_symbol_t);
-}
-
-static inline const char *symtab_entry_name(int entry)
-{
-	size_t index = symtab[entry].st_name;
-
-	if (index >= strtab_size)
-		return NULL;
-
-	return strtab + index;
-}
-
-static inline size_t symtab_next(size_t i)
-{
-	for (; i < symtab_len(); i++) {
-		const char *name = symtab_entry_name(i);
-		int st_bind = elf_st_bind(symtab[i].st_info);
-		int st_type = elf_st_type(symtab[i].st_info);
+
+static inline const char *symtab_entry_name(debug_sections_t *scs, int entry)
+{
+	size_t index = scs->symtab[entry].st_name;
+
+	if (index >= scs->strtab_size)
+		return NULL;
+
+	return scs->strtab + index;
+}
+
+static inline size_t symtab_next(debug_sections_t *scs, size_t i)
+{
+	size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
+
+	for (; i < symtab_len; i++) {
+		const char *name = symtab_entry_name(scs, i);
+		int st_bind = elf_st_bind(scs->symtab[i].st_info);
+		int st_type = elf_st_type(scs->symtab[i].st_info);
 
 		if (st_bind == STB_LOCAL)
@@ -82,6 +79,11 @@
 }
 
-const char *symtab_name_lookup(uintptr_t addr, uintptr_t *symbol_addr)
-{
+const char *symtab_name_lookup(uintptr_t addr, uintptr_t *symbol_addr, debug_sections_t *scs)
+{
+	const elf_symbol_t *symtab = scs->symtab;
+	size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
+	const char *strtab = scs->strtab;
+	size_t strtab_size = scs->strtab_size;
+
 	if (symtab == NULL || strtab == NULL)
 		return NULL;
@@ -90,5 +92,5 @@
 	uintptr_t closest_symbol_name = 0;
 
-	for (size_t i = symtab_next(0); i < symtab_len(); i = symtab_next(i + 1)) {
+	for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
 		if (symtab[i].st_value > addr)
 			continue;
@@ -132,5 +134,5 @@
 const char *symtab_fmt_name_lookup(uintptr_t addr)
 {
-	const char *name = symtab_name_lookup(addr, NULL);
+	const char *name = symtab_name_lookup(addr, NULL, &kernel_sections);
 	if (name == NULL)
 		name = "<unknown>";
@@ -150,7 +152,10 @@
 errno_t symtab_addr_lookup(const char *name, uintptr_t *addr)
 {
-	for (size_t i = symtab_next(0); i < symtab_len(); i = symtab_next(i + 1)) {
-		if (str_cmp(name, symtab_entry_name(i)) == 0) {
-			*addr = symtab[i].st_value;
+	debug_sections_t *scs = &kernel_sections;
+	size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
+
+	for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
+		if (str_cmp(name, symtab_entry_name(scs, i)) == 0) {
+			*addr = scs->symtab[i].st_value;
 			return EOK;
 		}
@@ -163,5 +168,8 @@
 void symtab_print_search(const char *name)
 {
-	if (symtab == NULL || strtab == NULL) {
+	debug_sections_t *scs = &kernel_sections;
+	size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
+
+	if (scs->symtab == NULL || scs->strtab == NULL) {
 		printf("No symbol information available.\n");
 		return;
@@ -170,9 +178,9 @@
 	size_t namelen = str_length(name);
 
-	for (size_t i = symtab_next(0); i < symtab_len(); i = symtab_next(i + 1)) {
-		const char *n = symtab_entry_name(i);
+	for (size_t i = symtab_next(scs, 0); i < symtab_len; i = symtab_next(scs, i + 1)) {
+		const char *n = symtab_entry_name(scs, i);
 
 		if (str_lcmp(name, n, namelen) == 0) {
-			printf("%p: %s\n", (void *) symtab[i].st_value, n);
+			printf("%p: %s\n", (void *) scs->symtab[i].st_value, n);
 		}
 	}
@@ -182,5 +190,8 @@
 const char *symtab_hints_enum(const char *input, const char **help, void **ctx)
 {
-	if (symtab == NULL || strtab == NULL)
+	debug_sections_t *scs = &kernel_sections;
+	size_t symtab_len = scs->symtab_size / sizeof(elf_symbol_t);
+
+	if (scs->symtab == NULL || scs->strtab == NULL)
 		return NULL;
 
@@ -189,6 +200,6 @@
 
 	size_t len = str_length(input);
-	for (size_t i = symtab_next((size_t) *ctx); i < symtab_len(); i = symtab_next(i + 1)) {
-		const char *curname = symtab_entry_name(i);
+	for (size_t i = symtab_next(scs, (size_t) *ctx); i < symtab_len; i = symtab_next(scs, i + 1)) {
+		const char *curname = symtab_entry_name(scs, i);
 
 		if (str_lcmp(input, curname, len) == 0) {
Index: kernel/generic/src/debug/util.c
===================================================================
--- kernel/generic/src/debug/util.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/debug/util.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -33,29 +33,4 @@
 #include <debug/names.h>
 
-/*
- * These declarations cause global definitions for the functions to be emitted
- * in this compilation unit, so if the compiler decides not to inline some of
- * them, only one external copy exists. See C99 inline rules.
- */
-extern inline uint8_t read_byte(const uint8_t **, const uint8_t *);
-extern inline uint16_t read_uint16(const uint8_t **, const uint8_t *);
-extern inline uint32_t read_uint24(const uint8_t **, const uint8_t *);
-extern inline uint32_t read_uint32(const uint8_t **, const uint8_t *);
-extern inline uint64_t read_uint64(const uint8_t **, const uint8_t *);
-extern inline uint64_t read_uint(const uint8_t **, const uint8_t *, unsigned);
-extern inline uint64_t read_uleb128(const uint8_t **, const uint8_t *);
-extern inline int64_t read_sleb128(const uint8_t **, const uint8_t *);
-extern inline void skip_leb128(const uint8_t **, const uint8_t *);
-extern inline uint64_t read_initial_length(const uint8_t **, const uint8_t *, unsigned *);
-extern inline const char *read_string(const uint8_t **, const uint8_t *);
-extern inline void skip_string(const uint8_t **, const uint8_t *);
-extern inline void safe_increment(const uint8_t **, const uint8_t *, ptrdiff_t);
-
-extern inline void skip_format(const uint8_t **, const uint8_t *, unsigned);
-extern inline void skip_formatted_entry(const uint8_t **, const uint8_t *,
-    const uint8_t *, const uint8_t *, unsigned);
-extern inline void skip_formatted_list(const uint8_t **, const uint8_t *,
-    unsigned, const uint8_t *, const uint8_t *, unsigned);
-
 bool skip_data(unsigned form, const uint8_t **const data,
     const uint8_t *data_end, unsigned width)
@@ -159,5 +134,5 @@
 }
 
-void print_formatted_list(const char *name,
+void print_formatted_list(debug_sections_t *scs, const char *name,
     const uint8_t *data, const uint8_t *const data_end,
     const uint8_t *format, const uint8_t *format_end,
@@ -175,5 +150,5 @@
 
 			DEBUGF("%s:%s:", dw_lnct_name(lnct), dw_form_name(form));
-			print_formed_data(form, &data, data_end, width);
+			print_formed_data(scs, form, &data, data_end, width);
 			DEBUGF("\n");
 		}
@@ -196,5 +171,5 @@
 }
 
-void print_formed_data(unsigned form, const uint8_t **const data,
+void print_formed_data(debug_sections_t *scs, unsigned form, const uint8_t **const data,
     const uint8_t *data_end, unsigned width)
 {
@@ -210,16 +185,16 @@
 	case DW_FORM_strp_sup:
 		offset = read_uint(data, data_end, width);
-		if (offset >= debug_str_size)
+		if (offset >= scs->debug_str_size)
 			DEBUGF("<out of range>");
 		else
-			DEBUGF("\"%s\"", debug_str + offset);
+			DEBUGF("\"%s\"", scs->debug_str + offset);
 		break;
 
 	case DW_FORM_line_strp:
 		offset = read_uint(data, data_end, width);
-		if (offset >= debug_line_str_size)
+		if (offset >= scs->debug_line_str_size)
 			DEBUGF("<out of range>");
 		else
-			DEBUGF("\"%s\"", debug_line_str + offset);
+			DEBUGF("\"%s\"", scs->debug_line_str + offset);
 		break;
 
Index: kernel/generic/src/debug/util.h
===================================================================
--- kernel/generic/src/debug/util.h	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/debug/util.h	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -33,4 +33,5 @@
 #include <stdint.h>
 #include <debug/constants.h>
+#include <debug/sections.h>
 #include <debug.h>
 
@@ -39,11 +40,11 @@
 extern bool skip_data(unsigned, const uint8_t **const, const uint8_t *, unsigned);
 extern void print_format(const char *, const uint8_t *, const uint8_t *);
-extern void print_formatted_list(const char *, const uint8_t *, const uint8_t *,
-    const uint8_t *, const uint8_t *, unsigned);
+extern void print_formatted_list(debug_sections_t *, const char *,
+    const uint8_t *, const uint8_t *, const uint8_t *, const uint8_t *, unsigned);
 
 extern void print_block(const uint8_t **, const uint8_t *, unsigned);
-extern void print_formed_data(unsigned, const uint8_t **const, const uint8_t *, unsigned);
-
-inline uint8_t read_byte(const uint8_t **data, const uint8_t *data_end)
+extern void print_formed_data(debug_sections_t *scs, unsigned, const uint8_t **const, const uint8_t *, unsigned);
+
+static inline uint8_t read_byte(const uint8_t **data, const uint8_t *data_end)
 {
 	if (*data >= data_end) {
@@ -67,5 +68,5 @@
 } __attribute__((packed));
 
-inline uint16_t read_uint16(const uint8_t **data, const uint8_t *data_end)
+static inline uint16_t read_uint16(const uint8_t **data, const uint8_t *data_end)
 {
 	if (*data + 2 > data_end) {
@@ -80,5 +81,5 @@
 }
 
-inline uint32_t read_uint24(const uint8_t **data, const uint8_t *data_end)
+static inline uint32_t read_uint24(const uint8_t **data, const uint8_t *data_end)
 {
 	if (*data + 3 > data_end) {
@@ -98,5 +99,5 @@
 }
 
-inline uint32_t read_uint32(const uint8_t **data, const uint8_t *data_end)
+static inline uint32_t read_uint32(const uint8_t **data, const uint8_t *data_end)
 {
 	if (*data + 4 > data_end) {
@@ -111,5 +112,5 @@
 }
 
-inline uint64_t read_uint64(const uint8_t **data, const uint8_t *data_end)
+static inline uint64_t read_uint64(const uint8_t **data, const uint8_t *data_end)
 {
 	if (*data + 8 > data_end) {
@@ -124,5 +125,5 @@
 }
 
-inline uint64_t read_uint(const uint8_t **data, const uint8_t *data_end, unsigned bytes)
+static inline uint64_t read_uint(const uint8_t **data, const uint8_t *data_end, unsigned bytes)
 {
 	switch (bytes) {
@@ -140,5 +141,5 @@
 }
 
-inline uint64_t read_uleb128(const uint8_t **data, const uint8_t *data_end)
+static inline uint64_t read_uleb128(const uint8_t **data, const uint8_t *data_end)
 {
 	uint64_t result = 0;
@@ -157,5 +158,5 @@
 }
 
-inline int64_t read_sleb128(const uint8_t **data, const uint8_t *data_end)
+static inline int64_t read_sleb128(const uint8_t **data, const uint8_t *data_end)
 {
 	uint64_t result = 0;
@@ -179,5 +180,5 @@
 }
 
-inline void skip_leb128(const uint8_t **data, const uint8_t *data_end)
+static inline void skip_leb128(const uint8_t **data, const uint8_t *data_end)
 {
 	while (*data < data_end) {
@@ -188,5 +189,5 @@
 }
 
-inline uint64_t read_initial_length(const uint8_t **data, const uint8_t *data_end, unsigned *width)
+static inline uint64_t read_initial_length(const uint8_t **data, const uint8_t *data_end, unsigned *width)
 {
 	uint32_t initial = read_uint32(data, data_end);
@@ -200,5 +201,5 @@
 }
 
-inline const char *read_string(const uint8_t **data, const uint8_t *data_end)
+static inline const char *read_string(const uint8_t **data, const uint8_t *data_end)
 {
 	const char *start = (const char *) *data;
@@ -218,10 +219,10 @@
 }
 
-inline void skip_string(const uint8_t **data, const uint8_t *data_end)
+static inline void skip_string(const uint8_t **data, const uint8_t *data_end)
 {
 	(void) read_string(data, data_end);
 }
 
-inline void safe_increment(const uint8_t **data,
+static inline void safe_increment(const uint8_t **data,
     const uint8_t *data_end, ptrdiff_t increment)
 {
@@ -235,5 +236,5 @@
 }
 
-inline void skip_format(const uint8_t **data, const uint8_t *const data_end,
+static inline void skip_format(const uint8_t **data, const uint8_t *const data_end,
     unsigned count)
 {
@@ -244,5 +245,5 @@
 }
 
-inline void skip_formatted_entry(const uint8_t **data, const uint8_t *const data_end,
+static inline void skip_formatted_entry(const uint8_t **data, const uint8_t *const data_end,
     const uint8_t *format, const uint8_t *format_end, unsigned width)
 {
@@ -256,5 +257,5 @@
 }
 
-inline void skip_formatted_list(const uint8_t **data, const uint8_t *const data_end,
+static inline void skip_formatted_list(const uint8_t **data, const uint8_t *const data_end,
     unsigned count,	const uint8_t *format, const uint8_t *format_end,
     unsigned width)
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/main/kinit.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -268,5 +268,5 @@
 		}
 
-		errno_t rc = program_create_from_image((void *) page, namebuf,
+		errno_t rc = program_create_from_image((void *) page, init.tasks[i].size, namebuf,
 		    &programs[i]);
 
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/proc/program.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -143,5 +143,5 @@
  *
  */
-errno_t program_create_from_image(void *image_addr, char *name, program_t *prg)
+errno_t program_create_from_image(void *image_addr, size_t image_size, char *name, program_t *prg)
 {
 	as_t *as = as_create(0);
@@ -157,6 +157,14 @@
 	}
 
-	return program_create(as, ((elf_header_t *) image_addr)->e_entry,
+	errno_t rc = program_create(as, ((elf_header_t *) image_addr)->e_entry,
 	    name, prg);
+
+	if (rc == EOK) {
+		prg->task->debug_sections = calloc(1, sizeof(debug_sections_t));
+		if (prg->task->debug_sections != NULL)
+			*prg->task->debug_sections = get_debug_sections(image_addr, image_size);
+	}
+
+	return rc;
 }
 
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision dcd821423a6084e9e2ec7fc7a6a9ae5065d0fd07)
+++ kernel/generic/src/proc/task.c	(revision 40eab9fdcc5233a31ae07d23360a0b5fc2e5c701)
@@ -225,4 +225,6 @@
 	task->answerbox.active = true;
 
+	task->debug_sections = NULL;
+
 #ifdef CONFIG_UDEBUG
 	/* Init debugging stuff */
