diff --git a/src/ld_so/debug.rs b/src/ld_so/debug.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8780cc1f268f6b5e15170363834a2909e770f145
--- /dev/null
+++ b/src/ld_so/debug.rs
@@ -0,0 +1,117 @@
+use crate::{c_str::CString, platform::types::*};
+use alloc::boxed::Box;
+
+#[repr(C)]
+pub enum RTLDState {
+    /// Mapping change is complete.
+    RT_CONSISTENT,
+    /// Beginning to add a new object.
+    RT_ADD,
+    /// Beginning to remove an object mapping.
+    RT_DELETE,
+}
+
+/// Data structure for sharing debugging information from the
+/// run-time dynamic linker for loaded ELF shared objects.
+#[repr(C)]
+pub struct RTLDDebug {
+    /// Version number for this protocol.
+    r_version: i32,
+    /// Head of the chain of loaded objects.
+    r_map: *mut LinkMap,
+    //struct link_map *r_map;
+    /// This is the address of a function internal to the run-time linker,
+    /// that will always be called when the linker begins to map in a
+    /// library or unmap it, and again when the mapping change is complete.
+    /// The debugger can set a breakpoint at this address if it wants to
+    /// notice shared object mapping changes.
+    pub r_brk: extern "C" fn(),
+
+    /// This state value describes the mapping change taking place when
+    /// the `r_brk' address is called.
+    pub state: RTLDState,
+
+    ///  Base address the linker is loaded at.
+    pub r_ldbase: usize,
+}
+
+impl RTLDDebug {
+    const NEW: Self = RTLDDebug {
+        r_version: 1,
+        r_map: 0 as *mut LinkMap,
+        r_brk: _dl_debug_state,
+        state: RTLDState::RT_CONSISTENT,
+        r_ldbase: 0,
+    };
+
+    pub fn insert(&mut self, l_addr: usize, name: &str, l_ld: usize) {
+        if self.r_map.is_null() {
+            self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
+        } else {
+            unsafe { (*self.r_map).add_object(l_addr, name, l_ld) };
+        }
+        return;
+    }
+}
+
+#[repr(C)]
+struct LinkMap {
+    /* These members are part of the protocol with the debugger.
+    This is the same format used in SVR4.  */
+    /// Difference between the address in the ELF
+    /// file and the addresses in memory.
+    l_addr: usize,
+    /// Absolute file name object was found in.
+    l_name: *const c_char,
+    /// Dynamic section of the shared object.
+    l_ld: usize,
+    l_next: *mut LinkMap,
+    l_prev: *mut LinkMap,
+}
+
+impl LinkMap {
+    fn new() -> *mut Self {
+        let map = Box::new(LinkMap {
+            l_addr: 0,
+            l_name: 0 as *const c_char,
+            l_ld: 0,
+            l_next: 0 as *mut LinkMap,
+            l_prev: 0 as *mut LinkMap,
+        });
+        Box::into_raw(map)
+    }
+
+    fn new_with_args(l_addr: usize, name: &str, l_ld: usize) -> *mut Self {
+        let map = LinkMap::new();
+        unsafe {
+            (*map).l_addr = l_addr;
+            (*map).l_ld = l_ld;
+            let c_name = CString::new(name).unwrap();
+            (*map).l_name = c_name.into_raw() as *const c_char;
+        }
+        map
+    }
+
+    fn add_object(&mut self, l_addr: usize, name: &str, l_ld: usize) {
+        let node = LinkMap::new_with_args(l_addr, name, l_ld);
+        let mut last = self;
+        while !last.l_next.is_null() {
+            last = unsafe { last.l_next.as_mut() }.unwrap();
+        }
+        unsafe {
+            (*node).l_prev = last;
+            (*last).l_next = node;
+        }
+    }
+}
+
+/*
+ * Gdb may be looking for this fuction with that exact name and set
+ * break point there
+ */
+#[linkage = "weak"]
+#[no_mangle]
+pub extern "C" fn _dl_debug_state() {}
+
+#[no_mangle]
+pub static mut _r_debug: RTLDDebug = RTLDDebug::NEW;
diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs
index 15c666711c436468b224c25e2754a6f9e8418665..818a5feb483b0e73e22f164f3c715e7026682334 100644
--- a/src/ld_so/linker.rs
+++ b/src/ld_so/linker.rs
@@ -4,9 +4,16 @@ use alloc::{
     string::{String, ToString},
     vec::Vec,
 };
-use core::{mem, ptr, slice};
+use core::{
+    mem::{size_of, transmute},
+    ptr, slice,
+};
 use goblin::{
-    elf::{program_header, reloc, sym, Elf},
+    elf::{
+        program_header,
+        r#dyn::{Dyn, DT_DEBUG},
+        reloc, sym, Elf,
+    },
     error::{Error, Result},
 };
 
@@ -19,6 +26,7 @@ use crate::{
 };
 
 use super::{
+    debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
     tcb::{Master, Tcb},
     PAGE_SIZE,
 };
@@ -197,6 +205,8 @@ impl Linker {
     }
 
     pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> {
+        unsafe { _r_debug.state = RTLDState::RT_ADD };
+        _dl_debug_state();
         let elfs = {
             let mut elfs = BTreeMap::new();
             for (name, data) in self.objects.iter() {
@@ -219,7 +229,8 @@ impl Linker {
                 Some(some) => some,
                 None => continue,
             };
-
+            // data for struct LinkMap
+            let mut l_ld = 0;
             // Calculate virtual memory bounds
             let bounds = {
                 let mut bounds_opt: Option<(usize, usize)> = None;
@@ -230,6 +241,9 @@ impl Linker {
                         ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
 
                     match ph.p_type {
+                        program_header::PT_DYNAMIC => {
+                            l_ld = ph.p_vaddr;
+                        }
                         program_header::PT_LOAD => {
                             if self.verbose {
                                 println!("  load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
@@ -284,6 +298,7 @@ impl Linker {
                         size,
                         sys_mman::PROT_READ | sys_mman::PROT_WRITE,
                     );
+                    _r_debug.insert(addr as usize, &elf_name, addr + l_ld as usize);
                     slice::from_raw_parts_mut(addr as *mut u8, size)
                 } else {
                     let ptr = sys_mman::mmap(
@@ -301,6 +316,7 @@ impl Linker {
                         return Err(Error::Malformed(format!("failed to map {}", elf_name)));
                     }
                     ptr::write_bytes(ptr as *mut u8, 0, size);
+                    _r_debug.insert(ptr as usize, &elf_name, ptr as usize + l_ld as usize);
                     slice::from_raw_parts_mut(ptr as *mut u8, size)
                 }
             };
@@ -541,6 +557,32 @@ impl Linker {
                 }
             }
 
+            // overwrite DT_DEBUG if exist in .dynamic section
+            for section in &elf.section_headers {
+                // we won't bother with half corrupted elfs.
+                let name = elf.shdr_strtab.get(section.sh_name).unwrap().unwrap();
+                if name != ".dynamic" {
+                    continue;
+                }
+                let mmap = match self.mmaps.get_mut(*elf_name) {
+                    Some(some) => some,
+                    None => continue,
+                };
+                let dyn_start = section.sh_addr as usize;
+                let bytes: [u8; size_of::<Dyn>() / 2] =
+                    unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
+                if let Some(dynamic) = elf.dynamic.as_ref() {
+                    let mut i = 0;
+                    for entry in &dynamic.dyns {
+                        if entry.d_tag == DT_DEBUG {
+                            let start = dyn_start + i * size_of::<Dyn>() + size_of::<Dyn>() / 2;
+                            mmap[start..start + size_of::<Dyn>() / 2].clone_from_slice(&bytes);
+                        }
+                        i += 1;
+                    }
+                }
+            }
+
             // Protect pages
             for ph in elf.program_headers.iter() {
                 if ph.p_type == program_header::PT_LOAD {
@@ -629,7 +671,7 @@ impl Linker {
 
                 if rel.r_type == reloc::R_X86_64_IRELATIVE {
                     unsafe {
-                        let f: unsafe extern "C" fn() -> u64 = mem::transmute(b + a);
+                        let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
                         set_u64(f());
                     }
                 }
@@ -670,7 +712,8 @@ impl Linker {
                 }
             }
         }
-
+        unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
+        _dl_debug_state();
         Ok(entry_opt)
     }
 }
diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs
index cbc27567bc503bffb8645fd90e8d9b23cb72ceba..1d06541ac15dfc6fcbeaac4a7498d1e503fb0486 100644
--- a/src/ld_so/mod.rs
+++ b/src/ld_so/mod.rs
@@ -5,10 +5,10 @@ use crate::start::Stack;
 
 pub const PAGE_SIZE: usize = 4096;
 
+pub mod debug;
 pub mod linker;
 pub mod start;
 pub mod tcb;
-
 pub fn static_init(sp: &'static Stack) {
     let mut phdr_opt = None;
     let mut phent_opt = None;
diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs
index 16075479925ddb0a794f37adf2968137953dc89d..1d60b714fd09efec0224f3ca52ebca64c0666a57 100644
--- a/src/ld_so/start.rs
+++ b/src/ld_so/start.rs
@@ -7,6 +7,7 @@ use crate::{
 };
 
 use super::{
+    debug::_r_debug,
     linker::{Linker, DSO},
     tcb::Tcb,
 };
@@ -130,6 +131,11 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
         true
     };
 
+    // we might need global lock for this kind of stuff
+    unsafe {
+        _r_debug.r_ldbase = ld_entry;
+    }
+
     // Some variables that will be overridden by environment and auxiliary vectors
     let library_path = match envs.get("LD_LIBRARY_PATH") {
         Some(lib_path) => lib_path,
diff --git a/src/platform/test/mod.rs b/src/platform/test/mod.rs
index 3ac5a17166659584384f2661af8051a3849e8dcc..01889bb3588b6f58ea662a474529eef9429a8e68 100644
--- a/src/platform/test/mod.rs
+++ b/src/platform/test/mod.rs
@@ -8,10 +8,7 @@ mod epoll;
 
 #[test]
 fn access() {
-    use crate::header::{
-        errno,
-        unistd,
-    };
+    use crate::header::{errno, unistd};
 
     //TODO: create test files
     assert_eq!(Sys::access(c_str!("not a file!"), unistd::F_OK), !0);
@@ -44,9 +41,7 @@ fn chdir() {
 
 #[test]
 fn clock_gettime() {
-    use crate::header::{
-        time
-    };
+    use crate::header::time;
 
     {
         let mut timespec = time::timespec {