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/common.h b/common.h
index c672913..6ca8430 100644
--- a/common.h
+++ b/common.h
@@ -217,6 +217,8 @@ extern void enable_all_breakpoints(Process * proc);
 extern void disable_all_breakpoints(Process * proc);
 extern void reinitialize_breakpoints(Process *);
 
+extern void linkmap_init(Process * proc, struct ltelf *lte);
+
 extern Process * open_program(char * filename, pid_t pid);
 extern void open_pid(pid_t pid);
 extern void show_summary(void);
@@ -245,9 +247,8 @@ 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 *);
-
-#if 0				/* not yet */
-extern int umoven(Process * proc, void * addr, int len, void * laddr);
-#endif
+extern void linkmap_init(Process *, struct ltelf *);
+extern int find_dynamic_entry_addr(Process *, void *, int, void **);
diff --git a/defs.h b/defs.h
index b694099..a741f8d 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..d0cd31a 100644
--- a/elf.c
+++ b/elf.c
@@ -17,9 +17,11 @@ static void do_close_elf(struct ltelf *lte);
 static 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);
+static int in_load_libraries(const char *name, struct ltelf *lte, GElf_Sym *sym);
 static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
 
+static struct library_symbol *library_symbols = NULL;
+
 #ifdef PLT_REINITALISATION_BP
 extern char *PLTs_initialized_by_here;
 #endif
@@ -33,7 +35,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);
@@ -141,6 +142,9 @@ do_init_elf(struct ltelf *lte, const char *filename) {
 		} else if (shdr.sh_type == SHT_DYNAMIC) {
 			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)
@@ -280,7 +284,7 @@ do_init_elf(struct ltelf *lte, const char *filename) {
 	if (!relplt_addr || !lte->plt_addr) {
 		debug(1, "%s has no PLT relocations", filename);
 		lte->relplt = NULL;
-		lte->relplt_count = 0;
+    lte->relplt_count = 0;
 	} else {
 		for (i = 1; i < lte->ehdr.e_shnum; ++i) {
 			Elf_Scn *scn;
@@ -302,7 +306,7 @@ do_init_elf(struct ltelf *lte, const char *filename) {
 					      "Couldn't get .rel*.plt data from \"%s\"",
 					      filename);
 				break;
-			}
+      }
 		}
 
 		if (i == lte->ehdr.e_shnum)
@@ -359,7 +363,7 @@ private_elf_gnu_hash(const char *name) {
 }
 
 static int
-in_load_libraries(const char *name, struct ltelf *lte) {
+in_load_libraries(const char *name, struct ltelf *lte, GElf_Sym *sym) {
 	size_t i;
 	unsigned long hash;
 	unsigned long gnu_hash;
@@ -369,7 +373,7 @@ in_load_libraries(const char *name, struct ltelf *lte) {
 
 	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 <= library_num; ++i) {
 		if (lte[i].hash == NULL)
 			continue;
 
@@ -394,15 +398,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 +425,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;
 
-				if (gelf_getsym(lte[i].dynsym, symndx, &sym) == NULL)
+				tmp = (sym) ? (sym) : (&tmp_sym);
+
+				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,7 +469,6 @@ 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;
@@ -465,98 +480,108 @@ read_elf(Process *proc) {
 	elf_version(EV_CURRENT);
 
 	do_init_elf(lte, proc->filename);
+
+	linkmap_init(proc, lte);
+
 	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;
+			if (in_load_libraries(name, lte, 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 +608,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, &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";
diff --git a/elf.h b/elf.h
index 426f7b8..60c4a7c 100644
--- a/elf.h
+++ b/elf.h
@@ -24,6 +24,10 @@ struct ltelf {
 	Elf32_Word *hash;
 	int hash_type;
 	int lte_flags;
+  GElf_Addr dyn_addr;
+  size_t dyn_sz;
+  size_t debug_offset;
+  GElf_Addr base_addr;
 #ifdef __mips__
 	size_t pltgot_addr;
 	size_t mips_local_gotno;
@@ -31,6 +35,8 @@ struct ltelf {
 #endif // __mips__
 };
 
+#define ELF_MAX_SEGMENTS  (50)
+#define ELF_SYMTAB_MAX    (5000)
 #define LTE_HASH_MALLOCED 1
 #define LTE_PLT_EXECUTABLE 2
 
diff --git a/options.c b/options.c
index aef73b1..b9b82c6 100644
--- a/options.c
+++ b/options.c
@@ -53,6 +53,7 @@ int opt_e_enable = 1;
 
 /* List of global function names given to -x: */
 struct opt_x_t *opt_x = NULL;
+unsigned int opt_x_cnt = 0;
 
 /* List of filenames give to option -F: */
 struct opt_F_t *opt_F = NULL;	/* alternate configuration file(s) */
@@ -98,6 +99,7 @@ usage(void) {
 		"  -T                  show the time spent inside each call.\n"
 		"  -u USERNAME         run command with the userid, groupid of username.\n"
 		"  -V, --version       output version information and exit.\n"
+		"  -g, --no-plt        disable breakpoints on PLT entries.\n"
 		"  -x NAME             treat the global NAME like a library subroutine.\n"
 #ifdef PLT_REINITALISATION_BP
 		"  -X NAME             same as -x; and PLT's will be initialized by here.\n"
@@ -179,6 +181,7 @@ char **
 process_options(int argc, char **argv) {
 	progname = argv[0];
 	options.output = stderr;
+	options.no_plt = 0;
 
 	guess_cols();
 
@@ -198,9 +201,10 @@ process_options(int argc, char **argv) {
 			{"library", 1, 0, 'l'},
 			{"output", 1, 0, 'o'},
 			{"version", 0, 0, 'V'},
+			{"no-plt", 0, 0, 'g'},
 			{0, 0, 0, 0}
 		};
-		c = getopt_long(argc, argv, "+cfhiLrStTV"
+		c = getopt_long(argc, argv, "+cfhiLrStTVg"
 # ifdef USE_DEMANGLE
 				"C"
 # endif
@@ -351,6 +355,9 @@ process_options(int argc, char **argv) {
 					"This is free software; see the GNU General Public Licence\n"
 					"version 2 or later for copying conditions.  There is NO warranty.\n");
 			exit(0);
+		case 'g':
+			options.no_plt = 1;
+			break;
 		case 'X':
 #ifdef PLT_REINITALISATION_BP
 			PLTs_initialized_by_here = optarg;
@@ -378,9 +385,11 @@ process_options(int argc, char **argv) {
 					perror("ltrace: malloc");
 					exit(1);
 				}
+				opt_x_cnt++;
 				p->name = optarg;
 				p->found = 0;
 				p->next = opt_x;
+				p->hash = ~(0UL);
 				opt_x = p;
 				break;
 			}
diff --git a/options.h b/options.h
index db253c5..f961ed3 100644
--- a/options.h
+++ b/options.h
@@ -14,6 +14,7 @@ struct options_t {
 	int arraylen; /* default maximum # of array elements printed */
 	int strlen;   /* default maximum # of bytes printed in strings */
 	int follow;   /* trace child processes */
+	int no_plt;   /* set bps on PLT entries */
 };
 extern struct options_t options;
 
@@ -40,6 +41,7 @@ struct opt_F_t {
 struct opt_x_t {
 	char *name;
 	int found;
+	unsigned long hash;
 	struct opt_x_t *next;
 };
 
@@ -51,5 +53,6 @@ extern int opt_e_enable;	/* 0 if '!' is used, 1 otherwise */
 extern struct opt_F_t *opt_F;	/* alternate configuration file(s) */
 
 extern struct opt_x_t *opt_x;	/* list of functions to break at */
+extern unsigned int opt_x_cnt;
 
 extern char **process_options(int argc, char **argv);
diff --git a/sysdeps/README b/sysdeps/README
index ce033ef..2ad591a 100644
--- a/sysdeps/README
+++ b/sysdeps/README
@@ -30,3 +30,5 @@ char * pid2name(pid_t pid);
 void trace_me(void);
 int trace_pid(pid_t pid);
 void untrace_pid(pid_t pid);
+void linkmap_init(Process *, struct ltelf *);
+int find_dynamic_entry_addr(Process *, void *, int, void **);
diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c
index e4d4063..5a94167 100644
--- a/sysdeps/linux-gnu/alpha/trace.c
+++ b/sysdeps/linux-gnu/alpha/trace.c
@@ -73,3 +73,6 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
 void
 save_register_args(enum tof type, Process *proc) {
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
index 10f7cc4..38f2dfe 100644
--- a/sysdeps/linux-gnu/arm/trace.c
+++ b/sysdeps/linux-gnu/arm/trace.c
@@ -129,3 +129,6 @@ save_register_args(enum tof type, Process *proc) {
 			memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg));
 	}
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/i386/trace.c b/sysdeps/linux-gnu/i386/trace.c
index 76f1105..dfc4813 100644
--- a/sysdeps/linux-gnu/i386/trace.c
+++ b/sysdeps/linux-gnu/i386/trace.c
@@ -1,5 +1,6 @@
 #include "config.h"
 
+#include <gelf.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -83,3 +84,36 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
 void
 save_register_args(enum tof type, Process *proc) {
 }
+
+int
+find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) {
+	int i = 0, done = 0;
+	Elf32_Dyn entry;
+
+	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
+
+	if (addr ==  NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
+		return -1;
+	}
+
+	while ((!done) && (i < ELF_MAX_SEGMENTS) &&
+			(sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
+			(entry.d_tag != DT_NULL)) {
+		if (entry.d_tag == d_tag) {
+			done = 1;
+			*addr = (void *)entry.d_un.d_val;
+		}
+		pvAddr += sizeof(entry);
+		i++;
+	}
+
+	if (done) {
+		debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
+		return 0;
+	}
+	else {
+		debug(2, "Couldn't address for dtag!\n");
+		return -1;
+	}
+}
+
diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
index 799e0ff..0f3a759 100644
--- a/sysdeps/linux-gnu/ia64/trace.c
+++ b/sysdeps/linux-gnu/ia64/trace.c
@@ -266,3 +266,6 @@ save_register_args(enum tof type, Process *proc) {
 void
 get_arch_dep(Process *proc) {
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
index 2f89fdf..6e2e699 100644
--- a/sysdeps/linux-gnu/m68k/trace.c
+++ b/sysdeps/linux-gnu/m68k/trace.c
@@ -87,3 +87,6 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
 void
 save_register_args(enum tof type, Process *proc) {
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c
index ff94930..da8bccc 100644
--- a/sysdeps/linux-gnu/mipsel/trace.c
+++ b/sysdeps/linux-gnu/mipsel/trace.c
@@ -165,3 +165,6 @@ save_register_args(enum tof type, Process *proc) {
 }
 
 /**@}*/
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
index 81fb71d..b83ca98 100644
--- a/sysdeps/linux-gnu/ppc/trace.c
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -153,3 +153,6 @@ arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
 	*result = pointed_to;
 	return 0;
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 4251c1d..777fc4e 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -1,6 +1,8 @@
 #include "config.h"
+#include "common.h"
 
 #include <sys/types.h>
+#include <link.h>
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
@@ -34,3 +36,73 @@ pid2name(pid_t pid) {
 	}
 	return NULL;
 }
+
+static void
+crawl_linkmap(Process *proc, struct ltelf *lte, struct link_map *lm) {
+	struct link_map rlm;
+	char lib_name[BUFSIZ];
+
+	debug (DEBUG_FUNCTION, "crawl_linkmap()");
+
+	while (lm) {
+		if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
+			debug(2, "Unable to read link map\n");
+			return;
+		}
+
+		lm = rlm.l_next;
+		if (rlm.l_name == NULL) {
+			debug(2, "Invalid library name referenced in dynamic linker map\n");
+			return;
+		}
+
+		umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
+
+		if (lib_name[0] == '\0') {
+			debug(2, "Library name is an empty string");
+			continue;
+		}
+
+		debug(2, "Object %s, Loaded at 0x%x\n", lib_name, rlm.l_addr);
+
+		if (library_num < MAX_LIBRARIES) {
+			library[library_num++] = strdup(lib_name);
+			lte[library_num].base_addr = rlm.l_addr;
+		}
+		else {
+			fprintf (stderr, "MAX LIBS REACHED\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+	return;
+}
+
+void
+linkmap_init(Process *proc, struct ltelf *lte) {
+	void *dbg_addr = NULL;
+	struct r_debug rdbg, *tdbg = NULL;
+	struct link_map *tlink_map = NULL;
+
+	debug(DEBUG_FUNCTION, "linkmap_init()");
+
+	if (find_dynamic_entry_addr(proc, (void *)lte->dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
+		debug(2, "Couldn't find debug structure!");
+		return;
+	}
+
+	tdbg = dbg_addr;
+
+	/* XXX
+	 * use r_debug's s_brk to watch for libs as they are added/removed
+	 */
+
+	if (umovebytes(proc, tdbg, &rdbg, sizeof(rdbg)) != sizeof(rdbg)) {
+		debug(2, "This process does not have a debug structure!\n");
+		return;
+	}
+
+	tlink_map = rdbg.r_map;
+	crawl_linkmap(proc, lte, tlink_map);
+
+	return;
+}
diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c
index 9df2437..5be80d2 100644
--- a/sysdeps/linux-gnu/s390/trace.c
+++ b/sysdeps/linux-gnu/s390/trace.c
@@ -196,3 +196,6 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
 void
 save_register_args(enum tof type, Process *proc) {
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c
index 7f05b55..d266d1a 100644
--- a/sysdeps/linux-gnu/sparc/trace.c
+++ b/sysdeps/linux-gnu/sparc/trace.c
@@ -79,3 +79,6 @@ save_register_args(enum tof type, Process *proc) {
 			memcpy(a->sysc_arg, &a->regs.u_regs[UREG_G7], sizeof(a->sysc_arg));
 	}
 }
+
+int find_dynamic_entry_addr(Process *, void *, int, void **){
+}
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index df5b090..1ce8c4e 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -84,6 +84,8 @@ trace_pid(pid_t pid) {
 		exit (1);
 	}
 
+  
+
 	return 0;
 }
 
@@ -163,6 +165,30 @@ continue_after_breakpoint(Process *proc, Breakpoint *sbp) {
 	}
 }
 
+size_t
+umovebytes(Process *proc, void *src, void *dest, size_t count) {
+  size_t bytes_read = 0;
+  long word = 0;
+  void *src_iter = src, *dest_iter = dest;
+  int min = 0, max = 0;
+
+  while (bytes_read < count) {
+    word = ptrace(PTRACE_PEEKDATA, proc->pid, src_iter, NULL);
+    if (errno != 0) {
+      return bytes_read; 
+    }
+
+    min = ((src_iter < src) ? (src - src_iter) : 0);
+    max = ((count - bytes_read) > sizeof(word) ? sizeof(word) : (count - bytes_read));
+    memcpy(dest_iter, (void *) ((unsigned long) &word + min), max - min);
+    bytes_read += max - min;
+    src_iter += sizeof(word);
+    dest_iter += max - min;
+
+  }
+  return bytes_read;
+}
+
 /* Read a series of bytes starting at the process's memory address
    'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
    have been read.
diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c
index 189734d..dbcda74 100644
--- a/sysdeps/linux-gnu/x86_64/trace.c
+++ b/sysdeps/linux-gnu/x86_64/trace.c
@@ -142,3 +142,35 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
 void
 save_register_args(enum tof type, Process *proc) {
 }
+
+int
+find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) {
+	int i = 0, done = 0;
+	Elf64_Dyn entry;
+
+	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
+
+	if (addr ==  NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
+		return -1;
+	}
+
+	while ((!done) && (i < ELF_MAX_SEGMENTS) &&
+			(sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
+			(entry.d_tag != DT_NULL)) {
+		if (entry.d_tag == d_tag) {
+			done = 1;
+			*addr = (void *)entry.d_un.d_val;
+		}
+		pvAddr += sizeof(entry);
+		i++;
+	}
+
+	if (done) {
+		debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
+		return 0;
+	}
+	else {
+		debug(2, "Couldn't address for dtag!\n");
+		return -1;
+	}
+}
