diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fc9b307
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+Makefile
+config.h
+ltrace
+*.a
+*.o
+sysdeps/linux-gnu/arch_syscallent.h
+sysdeps/linux-gnu/signalent.h
+sysdeps/linux-gnu/signalent1.h
+sysdeps/linux-gnu/syscallent.h
+sysdeps/linux-gnu/syscallent1.h
+sysdeps/linux-gnu/sysdep.h
diff --git a/README b/README
index ab1a2e5..b6bbb6a 100644
--- a/README
+++ b/README
@@ -37,6 +37,7 @@ people have contributed significantly to this project:
 * Ian Wienand <ianw@gelato.unsw.edu.au> (IA64 port)
 * Eric Vaitl <evaitl@cisco.com> (mipsel port)
 * Petr Machata <pmachata@redhat.com> (misc fixes)
+* Joe Damato <ice799@gmail.com> (libdl support, libunwind support)
 
 1. Introduction
 ---------------
diff --git a/common.h b/common.h
index c672913..7dacc98 100644
--- a/common.h
+++ b/common.h
@@ -1,3 +1,4 @@
+#include <libunwind.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <stdio.h>
@@ -172,6 +173,8 @@ struct Process {
 	struct library_symbol * list_of_symbols;
 
 	/* Arch-dependent: */
+	void * debug;	/* arch-dep process debug struct */
+	long debug_state; /* arch-dep debug state */
 	void * instruction_pointer;
 	void * stack_pointer;      /* To get return addr, args... */
 	void * return_addr;
@@ -186,6 +189,10 @@ struct Process {
 	/* output: */
 	enum tof type_being_displayed;
 
+	/* libunwind address space */
+	unw_addr_space_t unwind_as;
+	void *unwind_priv;
+
 	Process * next;
 };
 
@@ -222,6 +229,14 @@ extern void open_pid(pid_t pid);
 extern void show_summary(void);
 extern arg_type_info * lookup_prototype(enum arg_type at);
 
+extern void do_init_elf(struct ltelf *lte, const char *filename);
+extern void do_close_elf(struct ltelf *lte);
+extern int in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym);
+extern struct library_symbol *library_symbols;
+extern void add_library_symbol(GElf_Addr addr, const char *name,
+		struct library_symbol **library_symbolspp,
+		enum toplt type_of_plt, int is_weak);
+
 /* Arch-dependent stuff: */
 extern char * pid2name(pid_t pid);
 extern void trace_set_options(Process * proc, pid_t pid);
@@ -245,9 +260,11 @@ extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info
 extern void save_register_args(enum tof type, Process * proc);
 extern int umovestr(Process * proc, void * addr, int len, void * laddr);
 extern int umovelong (Process * proc, void * addr, long * result, arg_type_info * info);
+extern size_t umovebytes (Process *proc, void * src, void * dest, size_t count);
 extern int ffcheck(void * maddr);
 extern void * sym2addr(Process *, struct library_symbol *);
+extern int linkmap_init(Process *, struct ltelf *);
+extern void arch_check_dbg(Process *proc);
 
-#if 0				/* not yet */
-extern int umoven(Process * proc, void * addr, int len, void * laddr);
-#endif
+extern int libdl_hooked;
+extern struct ltelf main_lte;
diff --git a/configure b/configure
index d5392a0..ec6e4dc 100755
--- a/configure
+++ b/configure
@@ -14,6 +14,22 @@ echo -n "checking $PACKAGE_NAME version... "
 PACKAGE_VERSION=$( cat VERSION )
 echo $PACKAGE_VERSION
 
+echo -n "checking CPU architecture..."
+HOST_ARCH=$(uname -m)
+if [ "$HOST_ARCH" = "i686" ]
+then
+	HOST_ARCH="x86"
+elif [ "$HOST_ARCH" = "i386" ]
+then
+	HOST_ARCH="x86"
+elif [ "$HOST_ARCH" = "x86_64" ]
+then
+	HOST_ARCH="x86_64"
+else
+	HOST_ARCH="(unknown)"
+fi
+echo $HOST_ARCH
+
 echo -n "checking HOST_OS... "
 HOST_OS=$( uname -s )
 if [ "$HOST_OS" = "Linux" ]
@@ -80,7 +96,7 @@ rm -f conftest.c a.out
 CC=gcc
 CPPFLAGS=' -I /usr/include/libelf'
 CFLAGS='-g -O2'
-LIBS='-lelf -lsupc++ -liberty '
+LIBS="-lelf -lsupc++ -liberty -lunwind -lunwind-ptrace -lunwind-${HOST_ARCH}"
 INSTALL='/usr/bin/install -c'
 iquote='-iquote '
 iquoteend=''
diff --git a/defs.h b/defs.h
index b694099..dea000b 100644
--- a/defs.h
+++ b/defs.h
@@ -15,4 +15,4 @@
 #define DEFAULT_ARRAYLEN  4	/* default maximum # array elements */
 #endif				/* (-A switch) */
 
-#define MAX_LIBRARIES 30
+#define MAX_LIBRARIES 200
diff --git a/elf.c b/elf.c
index aeff211..cbda040 100644
--- a/elf.c
+++ b/elf.c
@@ -1,4 +1,4 @@
-# include "config.h"
+#include "config.h"
 
 #include <endian.h>
 #include <errno.h>
@@ -12,19 +12,24 @@
 
 #include "common.h"
 
-static void do_init_elf(struct ltelf *lte, const char *filename);
-static void do_close_elf(struct ltelf *lte);
-static void add_library_symbol(GElf_Addr addr, const char *name,
+void do_init_elf(struct ltelf *lte, const char *filename);
+void do_close_elf(struct ltelf *lte);
+void add_library_symbol(GElf_Addr addr, const char *name,
 			       struct library_symbol **library_symbolspp,
 			       enum toplt type_of_plt, int is_weak);
-static int in_load_libraries(const char *name, struct ltelf *lte);
+int in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym);
 static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
 
+struct library_symbol *library_symbols;
+struct ltelf main_lte;
+
 #ifdef PLT_REINITALISATION_BP
 extern char *PLTs_initialized_by_here;
 #endif
 
-static void
+int libdl_hooked = 0;
+
+void
 do_init_elf(struct ltelf *lte, const char *filename) {
 	int i;
 	GElf_Addr relplt_addr = 0;
@@ -33,7 +38,6 @@ do_init_elf(struct ltelf *lte, const char *filename) {
 	debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
 	debug(1, "Reading ELF from %s...", filename);
 
-	memset(lte, 0, sizeof(*lte));
 	lte->fd = open(filename, O_RDONLY);
 	if (lte->fd == -1)
 		error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
@@ -142,6 +146,9 @@ do_init_elf(struct ltelf *lte, const char *filename) {
 			Elf_Data *data;
 			size_t j;
 
+			lte->dyn_addr = shdr.sh_addr;
+			lte->dyn_sz = shdr.sh_size;
+
 			data = elf_getdata(scn, NULL);
 			if (data == NULL || elf_getdata(scn, data) != NULL)
 				error(EXIT_FAILURE, 0,
@@ -314,7 +321,7 @@ do_init_elf(struct ltelf *lte, const char *filename) {
 	}
 }
 
-static void
+void
 do_close_elf(struct ltelf *lte) {
 	debug(DEBUG_FUNCTION, "do_close_elf()");
 	if (lte->lte_flags & LTE_HASH_MALLOCED)
@@ -323,7 +330,7 @@ do_close_elf(struct ltelf *lte) {
 	close(lte->fd);
 }
 
-static void
+void
 add_library_symbol(GElf_Addr addr, const char *name,
 		   struct library_symbol **library_symbolspp,
 		   enum toplt type_of_plt, int is_weak) {
@@ -358,18 +365,18 @@ private_elf_gnu_hash(const char *name) {
 	return h & 0xffffffff;
 }
 
-static int
-in_load_libraries(const char *name, struct ltelf *lte) {
+int
+in_load_libraries(const char *name, struct ltelf *lte, size_t count, GElf_Sym *sym) {
 	size_t i;
 	unsigned long hash;
 	unsigned long gnu_hash;
 
-	if (!library_num)
+	if (!count)
 		return 1;
 
 	hash = elf_hash((const unsigned char *)name);
 	gnu_hash = private_elf_gnu_hash(name);
-	for (i = 1; i <= library_num; ++i) {
+	for (i = 0; i < count; ++i) {
 		if (lte[i].hash == NULL)
 			continue;
 
@@ -394,15 +401,20 @@ in_load_libraries(const char *name, struct ltelf *lte) {
 				do
 					if ((*hasharr & ~1u) == (gnu_hash & ~1u)) {
 						int symidx = hasharr - chain_zero;
-						GElf_Sym sym;
-
-						if (gelf_getsym(lte[i].dynsym, symidx, &sym) == NULL)
-							error(EXIT_FAILURE, 0,
-							      "Couldn't get symbol from .dynsym");
-
-						if (sym.st_value != 0
-						    && sym.st_shndx != SHN_UNDEF
-						    && strcmp(name, lte[i].dynstr + sym.st_name) == 0)
+						GElf_Sym tmp_sym;
+						GElf_Sym *tmp;
+
+						tmp = (sym) ? (sym) : (&tmp_sym);
+
+						if (gelf_getsym(lte[i].dynsym, symidx, tmp) == NULL)
+							error(EXIT_FAILURE, 0, "Couldn't get symbol from .dynsym");
+						else {
+							tmp->st_value += lte[i].base_addr;
+							debug(2, "symbol found: %s, %zd, %lx", name, i, tmp->st_value);
+						}
+						if (tmp->st_value != 0
+						    && tmp->st_shndx != SHN_UNDEF
+						    && strcmp(name, lte[i].dynstr + tmp->st_name) == 0)
 							return 1;
 					}
 				while ((*hasharr++ & 1u) == 0);
@@ -416,15 +428,22 @@ in_load_libraries(const char *name, struct ltelf *lte) {
 
 			for (symndx = buckets[hash % nbuckets];
 			     symndx != STN_UNDEF; symndx = chain[symndx]) {
-				GElf_Sym sym;
+				GElf_Sym tmp_sym;
+				GElf_Sym *tmp;
+
+				tmp = (sym) ? (sym) : (&tmp_sym);
 
-				if (gelf_getsym(lte[i].dynsym, symndx, &sym) == NULL)
+				if (gelf_getsym(lte[i].dynsym, symndx, tmp) == NULL)
 					error(EXIT_FAILURE, 0,
 					      "Couldn't get symbol from .dynsym");
+				else {
+					tmp->st_value += lte[i].base_addr;
+					debug(2, "symbol found: %s, %zd, %lx", name, i, tmp->st_value);
+				}
 
-				if (sym.st_value != 0
-				    && sym.st_shndx != SHN_UNDEF
-				    && strcmp(name, lte[i].dynstr + sym.st_name) == 0)
+				if (tmp->st_value != 0
+				    && tmp->st_shndx != SHN_UNDEF
+				    && strcmp(name, lte[i].dynstr + tmp->st_name) == 0)
 					return 1;
 			}
 		}
@@ -453,110 +472,128 @@ opd2addr(struct ltelf *lte, GElf_Addr addr) {
 
 struct library_symbol *
 read_elf(Process *proc) {
-	struct library_symbol *library_symbols = NULL;
 	struct ltelf lte[MAX_LIBRARIES + 1];
 	size_t i;
 	struct opt_x_t *xptr;
 	struct library_symbol **lib_tail = NULL;
 	int exit_out = 0;
+	int count  = 0;
 
 	debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename);
 
+	memset(lte, 0, sizeof(lte));
+
 	elf_version(EV_CURRENT);
 
 	do_init_elf(lte, proc->filename);
+
+	memcpy(&main_lte, lte, sizeof(struct ltelf));
+
+	if (opt_p && opt_p->pid > 0) {
+		linkmap_init(proc, lte);
+		libdl_hooked = 1;
+	}
+
 	proc->e_machine = lte->ehdr.e_machine;
-	for (i = 0; i < library_num; ++i)
+
+	for (i = 0; i < library_num; ++i) {
 		do_init_elf(&lte[i + 1], library[i]);
+	}
+
+	if (!options.no_plt) {
 #ifdef __mips__
-	// MIPS doesn't use the PLT and the GOT entries get changed
-	// on startup.
-	proc->need_to_reinitialize_breakpoints = 1;
-	for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
-		GElf_Sym sym;
-		const char *name;
-		GElf_Addr addr = arch_plt_sym_val(lte, i, 0);
-		if (gelf_getsym(lte->dynsym, i, &sym) == NULL){
-			error(EXIT_FAILURE, 0,
-					"Couldn't get relocation from \"%s\"",
-					proc->filename);
-		}
-		name=lte->dynstr+sym.st_name;
-		if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){
-			debug(2,"sym %s not a function",name);
-			continue;
+		// MIPS doesn't use the PLT and the GOT entries get changed
+		// on startup.
+		proc->need_to_reinitialize_breakpoints = 1;
+		for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
+			GElf_Sym sym;
+			const char *name;
+			GElf_Addr addr = arch_plt_sym_val(lte, i, 0);
+			if (gelf_getsym(lte->dynsym, i, &sym) == NULL){
+				error(EXIT_FAILURE, 0,
+						"Couldn't get relocation from \"%s\"",
+						proc->filename);
+			}
+			name=lte->dynstr+sym.st_name;
+			if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){
+				debug(2,"sym %s not a function",name);
+				continue;
+			}
+			add_library_symbol(addr, name, &library_symbols, 0,
+					ELF64_ST_BIND(sym.st_info) != 0);
+			if (!lib_tail)
+				lib_tail = &(library_symbols->next);
 		}
-		add_library_symbol(addr, name, &library_symbols, 0,
-				ELF64_ST_BIND(sym.st_info) != 0);
-		if (!lib_tail)
-			lib_tail = &(library_symbols->next);
-	}
 #else
-	for (i = 0; i < lte->relplt_count; ++i) {
-		GElf_Rel rel;
-		GElf_Rela rela;
-		GElf_Sym sym;
-		GElf_Addr addr;
-		void *ret;
-		const char *name;
+		for (i = 0; i < lte->relplt_count; ++i) {
+			GElf_Rel rel;
+			GElf_Rela rela;
+			GElf_Sym sym;
+			GElf_Addr addr;
+			void *ret;
+			const char *name;
+
+			if (lte->relplt->d_type == ELF_T_REL) {
+				ret = gelf_getrel(lte->relplt, i, &rel);
+				rela.r_offset = rel.r_offset;
+				rela.r_info = rel.r_info;
+				rela.r_addend = 0;
+			} else
+				ret = gelf_getrela(lte->relplt, i, &rela);
 
-		if (lte->relplt->d_type == ELF_T_REL) {
-			ret = gelf_getrel(lte->relplt, i, &rel);
-			rela.r_offset = rel.r_offset;
-			rela.r_info = rel.r_info;
-			rela.r_addend = 0;
-		} else
-			ret = gelf_getrela(lte->relplt, i, &rela);
-
-		if (ret == NULL
-		    || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
-		    || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
-				   &sym) == NULL)
-			error(EXIT_FAILURE, 0,
-			      "Couldn't get relocation from \"%s\"",
-			      proc->filename);
+			if (ret == NULL
+					|| ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
+					|| gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
+						&sym) == NULL)
+				error(EXIT_FAILURE, 0,
+						"Couldn't get relocation from \"%s\"",
+						proc->filename);
 
 #ifdef PLT_REINITALISATION_BP
-		if (!sym.st_value && PLTs_initialized_by_here)
-			proc->need_to_reinitialize_breakpoints = 1;
+			if (!sym.st_value && PLTs_initialized_by_here)
+				proc->need_to_reinitialize_breakpoints = 1;
 #endif
 
-		name = lte->dynstr + sym.st_name;
-		if (in_load_libraries(name, lte)) {
-			addr = arch_plt_sym_val(lte, i, &rela);
-			add_library_symbol(addr, name, &library_symbols,
-					   (PLTS_ARE_EXECUTABLE(lte)
-					   ?  LS_TOPLT_EXEC : LS_TOPLT_POINT),
-					   ELF64_ST_BIND(sym.st_info) == STB_WEAK);
-			if (!lib_tail)
-				lib_tail = &(library_symbols->next);
+			name = lte->dynstr + sym.st_name;
+			count = library_num ? library_num+1 : 0;
+			if (in_load_libraries(name, lte, count, NULL)) {
+				addr = arch_plt_sym_val(lte, i, &rela);
+				add_library_symbol(addr, name, &library_symbols,
+						(PLTS_ARE_EXECUTABLE(lte)
+						 ?	LS_TOPLT_EXEC : LS_TOPLT_POINT),
+						ELF64_ST_BIND(sym.st_info) == STB_WEAK);
+				if (!lib_tail)
+					lib_tail = &(library_symbols->next);
+			}
 		}
-	}
 #endif // !__mips__
 #ifdef PLT_REINITALISATION_BP
-	struct opt_x_t *main_cheat;
-
-	if (proc->need_to_reinitialize_breakpoints) {
-		/* Add "PLTs_initialized_by_here" to opt_x list, if not
-		   already there. */
-		main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
-		if (main_cheat == NULL)
-			error(EXIT_FAILURE, 0, "Couldn't allocate memory");
-		main_cheat->next = opt_x;
-		main_cheat->found = 0;
-		main_cheat->name = PLTs_initialized_by_here;
-
-		for (xptr = opt_x; xptr; xptr = xptr->next)
-			if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
-			    && main_cheat) {
-				free(main_cheat);
-				main_cheat = NULL;
-				break;
-			}
-		if (main_cheat)
-			opt_x = main_cheat;
-	}
+		struct opt_x_t *main_cheat;
+
+		if (proc->need_to_reinitialize_breakpoints) {
+			/* Add "PLTs_initialized_by_here" to opt_x list, if not
+				 already there. */
+			main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
+			if (main_cheat == NULL)
+				error(EXIT_FAILURE, 0, "Couldn't allocate memory");
+			main_cheat->next = opt_x;
+			main_cheat->found = 0;
+			main_cheat->name = PLTs_initialized_by_here;
+
+			for (xptr = opt_x; xptr; xptr = xptr->next)
+				if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
+						&& main_cheat) {
+					free(main_cheat);
+					main_cheat = NULL;
+					break;
+				}
+			if (main_cheat)
+				opt_x = main_cheat;
+		}
 #endif
+	} else {
+		lib_tail = &library_symbols;
+	}
 
 	for (i = 0; i < lte->symtab_count; ++i) {
 		GElf_Sym sym;
@@ -583,6 +620,28 @@ read_elf(Process *proc) {
 				break;
 			}
 	}
+
+	int found_count = 0;
+
+	for (xptr = opt_x; xptr; xptr = xptr->next) {
+		if (xptr->found)
+			continue;
+
+		GElf_Sym sym;
+		GElf_Addr addr;
+		if (in_load_libraries(xptr->name, lte, library_num+1, &sym)) {
+			debug(2, "found symbol %s @ %lx, adding it.", xptr->name, sym.st_value);
+			addr = sym.st_value;
+			add_library_symbol(addr, xptr->name, lib_tail, LS_TOPLT_NONE, 0);
+			xptr->found = 1;
+			found_count++;
+		}
+		if (found_count == opt_x_cnt){
+			debug(2, "done, found everything: %d\n", found_count);
+			break;
+		}
+	}
+
 	for (xptr = opt_x; xptr; xptr = xptr->next)
 		if ( ! xptr->found) {
 			char *badthing = "WARNING";
@@ -605,8 +664,8 @@ read_elf(Process *proc) {
 			}
 #endif
 			fprintf (stderr,
-				 "%s: Couldn't find symbol \"%s\" in file \"%s"
-			         "\"\n", badthing, xptr->name, proc->filename);
+				 "%s: Couldn't find symbol \"%s\" in file \"%s\" assuming it will be loaded by libdl!"
+				 "\n", badthing, xptr->name, proc->filename);
 		}
 	if (exit_out) {
 		exit (1);
