jaydeep created this revision.
jaydeep added a reviewer: clayborg.
jaydeep added subscribers: lldb-commits, bhushan, sagar, mohit.bhakkad, 
nitesh.jain.
jaydeep set the repository for this revision to rL LLVM.

This patch enables setting of breakpoints and disassembly for microMIPS 
applications running on bare-iron targets like IASim.

MIPS uses bit #0 (ISA bit) of an address for ISA mode (1 for microMIPS/MIPS16 
and 0 for MIPS). The resulting address is called as compressed address when ISA 
bit is set. This allows processor to switch between microMIPS and MIPS without 
any need for special mode-control register. This bit is then cleared by the 
processor while fetching the instruction from memory. However, apart from 
.debug_line, none of the ELF/DWARF sections set the ISA bit. 

In this patch:
1)      The symbol table is recorded in the form of compressed address for 
microMIPS symbols, so that corresponding debug_line can be decoded properly.
2)      Memory read/write of compressed address has been handled


Repository:
  rL LLVM

http://reviews.llvm.org/D12079

Files:
  source/Core/Disassembler.cpp
  source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
  source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1273,6 +1273,51 @@
 
             assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
 
+            /*
+             * MIPS:
+             * The bit #0 of an address is used for ISA mode (1 for microMIPS, 0 for MIPS).
+             * This allows processer to switch between microMIPS and MIPS without any need
+             * for special mode-control register. However, apart from .debug_line, none of
+             * the ELF/DWARF sections set the ISA bit (for symbol or section).
+             *
+             * Find first symbol with name func_name and type FUNC. If this is a microMIPS
+             * symbol then adjust func_range accordingly.
+            */
+            ArchSpec arch;
+            GetObjectFile()->GetArchitecture(arch);
+
+            if (arch.GetMachine() == llvm::Triple::mips64
+                || arch.GetMachine() == llvm::Triple::mips64el
+                || arch.GetMachine() == llvm::Triple::mips
+                || arch.GetMachine() == llvm::Triple::mipsel)
+            {
+                Symbol *microsym = NULL;
+                if (m_obj_file)
+                {
+                    Symtab *symtab = m_obj_file->GetSymtab ();
+                    if (symtab)
+                    {
+                        lldb::LanguageType language = ParseCompileUnitLanguage(sc);
+                        microsym = symtab->FindFirstSymbolWithNameAndType (func_name.GetDemangledName(language),
+                                                                           eSymbolTypeCode,
+                                                                           Symtab::eDebugNo,
+                                                                           Symtab::eVisibilityAny);
+
+                        if (microsym != NULL)
+                        {
+                            lldb::addr_t addr = microsym->GetFileAddress();
+
+                            // If address is compressed then it is a microMIPS symbol
+                            if (addr & 1)
+                            {
+                                Address &compressed_addr = func_range.GetBaseAddress();
+                                compressed_addr.SetOffset (compressed_addr.GetOffset() | 1);
+                            }
+                        }
+                    }
+                }
+            }
+
             if (FixupAddress (func_range.GetBaseAddress()))
             {
                 const user_id_t func_user_id = MakeUserID(die->GetOffset());
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3169,7 +3169,8 @@
     user_id_t site_id = bp_site->GetID();
 
     // Get the breakpoint address
-    const addr_t addr = bp_site->GetLoadAddress();
+    const addr_t load_addr = bp_site->GetLoadAddress();
+    addr_t addr = load_addr;
 
     // Log that a breakpoint was requested
     if (log)
@@ -3183,6 +3184,24 @@
         return error;
     }
 
+    /*
+     * MIPS:
+     * If bit #0 of an address (ISA bit) is set, then this is microMIPS or MIPS16 address.
+     * Processor clears this bit before fetching the instruction from memory. Set this
+     * breakpoint at uncompressed address.
+    */
+    const ArchSpec target_arch = GetTarget().GetArchitecture();
+    if (target_arch.GetMachine() == llvm::Triple::mips || target_arch.GetMachine() == llvm::Triple::mipsel 
+        || target_arch.GetMachine() == llvm::Triple::mips64 || target_arch.GetMachine() == llvm::Triple::mips64el)
+    {
+        if ((addr & 1))
+        {
+            addr = addr & (~1);
+            if (log)
+                log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") uncompressed address = 0x%" PRIx64, site_id, (uint64_t)addr);
+        }
+    }
+
     // Get the software breakpoint trap opcode size
     const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site);
 
@@ -3275,6 +3294,24 @@
     if (log)
         log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr);
 
+    /*
+     * MIPS:
+     * If bit #0 of an address (ISA bit) is set, then this is microMIPS or MIPS16 address.
+     * Processor clears this bit before fetching the instruction from memory. Use
+     * uncompressed address to disable this breakpoint.
+    */
+    const ArchSpec target_arch = GetTarget().GetArchitecture();
+    if (target_arch.GetMachine() == llvm::Triple::mips || target_arch.GetMachine() == llvm::Triple::mipsel 
+        || target_arch.GetMachine() == llvm::Triple::mips64 || target_arch.GetMachine() == llvm::Triple::mips64el)
+    {
+        if ((addr & 1))
+        {
+            addr = addr & (~1);
+            if (log)
+                log->Printf("ProcessGDBRemote::DisableBreakpointSite (size_id = %" PRIu64 ") uncompressed address = 0x%" PRIx64, site_id, (uint64_t)addr);
+        }
+    }
+
     if (bp_site->IsEnabled())
     {
         const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
Index: source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
===================================================================
--- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1814,6 +1814,10 @@
     }
 }
 
+#define STO_MIPS_ISA            (3 << 6)
+#define STO_MICROMIPS           (2 << 6)
+#define IS_MICROMIPS(ST_OTHER)  (((ST_OTHER) & STO_MIPS_ISA) == STO_MICROMIPS)
+
 // private
 unsigned
 ObjectFileELF::ParseSymbols (Symtab *symtab,
@@ -2091,6 +2095,22 @@
                 mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) );
         }
 
+        /*
+         * MIPS:
+         * The bit #0 of an address is used for ISA mode (1 for microMIPS, 0 for MIPS).
+         * This allows processer to switch between microMIPS and MIPS without any need
+         * for special mode-control register. However, apart from .debug_line, none of
+         * the ELF/DWARF sections set the ISA bit (for symbol or section). Use st_other
+         * flag to check whether the symbol is microMIPS and then set the ISA bit
+         * accordingly.
+        */
+        if (IS_MICROMIPS(symbol.st_other) &&
+            (arch.GetMachine() == llvm::Triple::mips64
+            || arch.GetMachine() == llvm::Triple::mips64el
+            || arch.GetMachine() == llvm::Triple::mips
+            || arch.GetMachine() == llvm::Triple::mipsel))
+            symbol_value = (symbol_value | 1);      // Set ISA bit
+
         Symbol dc_symbol(
             i + start_id,       // ID is the original symbol table index.
             mangled,
Index: source/Core/Disassembler.cpp
===================================================================
--- source/Core/Disassembler.cpp
+++ source/Core/Disassembler.cpp
@@ -1165,7 +1165,28 @@
 
         Error error;
         lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
-        const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(),
+
+        /*
+         * MIPS:
+         * The bit #0 of an address is used for ISA mode (1 for microMIPS, 0 for MIPS).
+         * This allows processer to switch between microMIPS and MIPS without any need
+         * for special mode-control register. If the address specified in the 'range'
+         * is a microMIPS address then clear bit #0 and fetch opcode from the memory.
+        */
+        Address compressed_addr = range.GetBaseAddress();
+        if (m_arch.GetMachine() == llvm::Triple::mips64
+            || m_arch.GetMachine() == llvm::Triple::mips64el
+            || m_arch.GetMachine() == llvm::Triple::mips
+            || m_arch.GetMachine() == llvm::Triple::mipsel)
+        {
+            if ((m_arch.GetFlags() | ArchSpec::eMIPSAse_micromips) == ArchSpec::eMIPSAse_micromips
+                || (m_arch.GetFlags() | ArchSpec::eMIPSAse_mips16) == ArchSpec::eMIPSAse_mips16)
+            {
+                compressed_addr.SetOffset (compressed_addr.GetOffset() & (~1));
+            }
+        }
+
+        const size_t bytes_read = target->ReadMemory (compressed_addr.GetFileAddress(),
                                                       prefer_file_cache, 
                                                       heap_buffer->GetBytes(), 
                                                       heap_buffer->GetByteSize(), 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to