Improve ARM thumb disassembler output.

Added BFI/BFC, LDRH.W/LDRSH.W, LDR (from pc), and B (conditional).

Change-Id: Iaf17520e0643b9e2da9e649a5d99f0274ece7529
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index ea7a216..eb0ca8a 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -624,6 +624,24 @@
             args << Rd << ", " << Rn << ", #" << imm12;
             break;
           }
+          case 0x16: {
+            // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii
+            ArmRegister Rd(instr, 8);
+            ArmRegister Rn(instr, 16);
+            uint32_t msb = instr & 0x1F;
+            uint32_t imm2 = (instr >> 6) & 0x3;
+            uint32_t imm3 = (instr >> 12) & 0x7;
+            uint32_t lsb = (imm3 << 2) | imm2;
+            uint32_t width = msb - lsb + 1;
+            if (Rn.r != 0xF) {
+              opcode << "bfi";
+              args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
+            } else {
+              opcode << "bfc";
+              args << Rd << ", #" << lsb << ", #" << width;
+            }
+            break;
+          }
           default:
             break;
         }
@@ -797,6 +815,50 @@
 
           break;
         }
+        case 0x03: case 0x0B: case 0x13: case 0x1B: { // 00xx011
+          // Load halfword
+          // |111|11|10|0 0|00|0|0000|1111|110000|000000|
+          // |5 3|21|09|8 7|65|4|3  0|5  2|10   6|5    0|
+          // |---|--|--|---|--|-|----|----|------|------|
+          // |332|22|22|2 2|22|2|1111|1111|110000|000000|
+          // |1 9|87|65|4 3|21|0|9  6|5  2|10   6|5    0|
+          // |---|--|--|---|--|-|----|----|------|------|
+          // |111|11|00|op3|01|1| Rn | Rt | op4  |      |
+          // |111|11| op2       |    |    | imm12       |
+          uint32_t op3 = (instr >> 23) & 3;
+          ArmRegister Rn(instr, 16);
+          ArmRegister Rt(instr, 12);
+          if (Rt.r != 15) {
+            if (op3 == 1) {
+              // LDRH.W Rt, [Rn, #imm12]       - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii
+              uint32_t imm12 = instr & 0xFFF;
+              opcode << "ldrh.w";
+              args << Rt << ", [" << Rn << ", #" << imm12 << "]";
+              if (Rn.r == 9) {
+                args << "  ; ";
+                Thread::DumpThreadOffset(args, imm12, 4);
+              } else if (Rn.r == 15) {
+                intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
+                lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
+                args << "  ; " << reinterpret_cast<void*>(*reinterpret_cast<int32_t*>(lit_adr));
+              }
+            } else if (op3 == 3) {
+              // LDRSH.W Rt, [Rn, #imm12]      - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii
+              uint32_t imm12 = instr & 0xFFF;
+              opcode << "ldrsh.w";
+              args << Rt << ", [" << Rn << ", #" << imm12 << "]";
+              if (Rn.r == 9) {
+                args << "  ; ";
+                Thread::DumpThreadOffset(args, imm12, 4);
+              } else if (Rn.r == 15) {
+                intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
+                lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
+                args << "  ; " << reinterpret_cast<void*>(*reinterpret_cast<int32_t*>(lit_adr));
+              }
+            }
+          }
+          break;
+        }
         case 0x05: case 0x0D: case 0x15: case 0x1D: { // 00xx101
           // Load word
           // |111|11|10|0 0|00|0|0000|1111|110000|000000|
@@ -991,6 +1053,11 @@
         default:
           break;
       }
+    } else if (opcode1 == 0x12 || opcode1 == 0x13) {  // 01001x
+      ThumbRegister Rt(instr, 8);
+      uint16_t imm8 = instr & 0xFF;
+      opcode << "ldr";
+      args << Rt << ", [pc, #" << (imm8 << 2) << "]";
     } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) ||  // 0101xx
                (opcode1 >= 0x18 && opcode1 <= 0x1f) ||  // 011xxx
                (opcode1 >= 0x20 && opcode1 <= 0x27)) {  // 100xxx
@@ -1039,6 +1106,12 @@
         }
         args << Rt << ", [" << Rn << ", #" << imm5 << "]";
       }
+    } else if (opcode1 >= 0x34 && opcode1 <= 0x37) {  // 1101xx
+      uint32_t imm8 = instr & 0xFF;
+      uint32_t cond = (instr >> 8) & 0xF;
+      opcode << "b";
+      DumpCond(opcode, cond);
+      DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1));
     } else if ((instr & 0xF800) == 0xA800) {
       // Generate SP-relative address
       ThumbRegister rd(instr, 8);