1structure arm_disassemblerLib :> arm_disassemblerLib = 2struct 3 4(* interactive use: 5 app load ["arm_parserLib", "arm_encoderLib"]; 6*) 7 8open HolKernel boolLib bossLib; 9open armSyntax arm_astSyntax; 10 11(* ------------------------------------------------------------------------- *) 12 13val _ = numLib.prefer_num(); 14val _ = wordsLib.prefer_word(); 15 16val ERR = Feedback.mk_HOL_ERR "arm_disassemblerLib"; 17 18(* ------------------------------------------------------------------------- *) 19 20val eval = boolSyntax.rhs o Thm.concl o bossLib.EVAL; 21 22val uint_of_word = wordsSyntax.uint_of_word; 23val sint_of_term = Arbint.toInt o intSyntax.int_of_term; 24val hex_of_word = Int.fmt StringCvt.HEX o uint_of_word; 25 26fun mk_word2 i = wordsSyntax.mk_wordii (i,2); 27fun mk_word4 i = wordsSyntax.mk_wordii (i,4); 28 29val SP = mk_word4 13; 30val AL = mk_word4 14; 31val PC = mk_word4 15; 32 33val is_T = Term.term_eq T; 34val is_F = Term.term_eq F; 35val is_SP = Term.term_eq SP; 36val is_AL = Term.term_eq AL; 37val is_PC = Term.term_eq PC; 38 39fun is_0 tm = uint_of_word tm = 0; 40 41val dest_strip = armSyntax.dest_strip; 42 43fun i2l i = 44let fun recurse n l = 45 if n = 0 then List.rev l 46 else recurse (n div 2) ((n mod 2 = 1)::l) 47in 48 if i < 0 then 49 raise ERR "i2l" "negative" 50 else if i = 0 then 51 [false] 52 else 53 recurse i [] 54end; 55 56(* ------------------------------------------------------------------------- *) 57 58val comma = ", "; 59val uppercase = String.map Char.toUpper; 60val commy = String.concat o Lib.separate comma; 61fun square s = String.concat ["[",s,"]"]; 62fun curly s = String.concat ["{",s,"}"]; 63val scommy = square o commy; 64fun opt b c x = if b then x ^ c else x 65 66fun code_line s1 s2 = (s1,s2) : string * string; 67fun directive_line s1 s2 = code_line (uppercase s1) s2; 68 69fun disassemble_ascii s = directive_line "ascii" (Lib.quote s); 70 71local 72 val tm_g = Parse.term_grammar () 73 val ty_g = Parse.type_grammar () 74in 75 val term_to_string = 76 PP.pp_to_string 70 77 (Parse.mlower o term_pp.pp_term tm_g ty_g PPBackEnd.raw_terminal) 78end 79 80fun disassemble_byte l = 81 l |> List.map term_to_string |> commy |> directive_line "byte" 82 83fun disassemble_short l = 84 l |> List.map term_to_string |> commy |> directive_line "short" 85 86fun disassemble_word l = 87 l |> List.map term_to_string |> commy |> directive_line "word" 88 89(* ------------------------------------------------------------------------- *) 90 91fun number tm = 92let val s = term_to_string tm in 93 if s = "ARB" then 94 "UNPREDICTABLE" 95 else 96 String.extract(s,0,SOME (String.size s - 1)) 97end; 98 99fun constant tm = "#" ^ number tm; 100fun sign_constant (u,tm) = (if is_T u then "#" else "#-") ^ number tm; 101 102fun offset tm = 103let val s = tm |> integer_wordSyntax.mk_w2i |> eval |> term_to_string in 104 if String.sub (s,0) = #"-" then 105 "-#" ^ String.extract(s,1,SOME (String.size s - 1)) 106 else 107 "+#" ^ s 108end; 109 110fun char_word4 c n = 111let val _ = 0 <= n andalso n <= 15 orelse raise ERR "char_word4" "" in 112 String.str c ^ Int.toString n 113end; 114 115fun reg 13 = "sp" 116 | reg 14 = "lr" 117 | reg 15 = "pc" 118 | reg n = char_word4 #"r" n; 119 120val register = reg o uint_of_word; 121val cregister = (char_word4 #"c") o uint_of_word; 122val coprocessor = (char_word4 #"p") o uint_of_word; 123val rcommy = commy o List.map register; 124 125local 126 fun mk_blocks l = 127 let 128 fun blocks [] i ys = ys 129 | blocks [false] i ys = ys 130 | blocks [true] i [] = [(i,i)] 131 | blocks [true] i (h::t) = ((fst h,i)::t) 132 | blocks (false::false::xs) i ys = blocks (false::xs) (i + 1) ys 133 | blocks (true::true::xs) i ys = blocks (true::xs) (i + 1) ys 134 | blocks (false::true::xs) i ys = 135 blocks (true::xs) (i + 1) ((i + 1,~1)::ys) 136 | blocks (true::false::xs) i [] = 137 blocks (false::xs) (i + 1) [(i,i)] 138 | blocks (true::false::xs) i (h::t) = 139 blocks (false::xs) (i + 1) ((fst h,i)::t) 140 in 141 List.rev (blocks l 0 (if hd l then [(0,~1)] else [])) 142 end 143 144 fun reg_list s [] = s ^ "}" 145 | reg_list s ((i,j)::xs) = 146 reg_list (s ^ reg i ^ 147 (if i = j then 148 "" 149 else if i + 1 = j then 150 comma ^ reg j 151 else 152 "-" ^ reg j) ^ 153 (if xs = [] then "" else comma)) xs 154in 155 val register_list = 156 (reg_list "{") o mk_blocks o i2l o 157 (fn i => i mod 0x10000) o uint_of_word 158end; 159 160fun full_condition tm = 161 case uint_of_word tm 162 of 0 => "eq" 163 | 1 => "ne" 164 | 2 => "cs" 165 | 3 => "cc" 166 | 4 => "mi" 167 | 5 => "pl" 168 | 6 => "vs" 169 | 7 => "vc" 170 | 8 => "hi" 171 | 9 => "ls" 172 | 10 => "ge" 173 | 11 => "lt" 174 | 12 => "gt" 175 | 13 => "le" 176 | 14 => "al" 177 | _ => raise ERR "full_condition" "unexpected value"; 178 179fun condition tm = 180 if Term.is_var tm then 181 fst (Term.dest_var tm) 182 else if is_AL tm orelse is_PC tm then 183 "" 184 else 185 full_condition tm; 186 187fun mnemonic (enc,cond,tm) s1 s2 = 188let 189 val q = if enc = Encoding_Thumb2_tm andalso 190 can arm_encoderLib.arm_encode 191 (arm_parserLib.Instruction (Encoding_Thumb_tm,cond,tm)) 192 then 193 ".w" 194 else 195 "" 196in 197 code_line (s1 ^ condition cond ^ q) s2 198end; 199 200fun arm_expand_imm tm = 201 ``(((7 >< 0) ^tm) #>> (2 * (w2n ((11 -- 8) ^tm)))) : word32`` 202 |> eval; 203 204fun thumb_expand_imm tm = 205 ``if (11 -- 10) ^tm = 0b00w then 206 let imm8 = (7 >< 0) ^tm : word8 in 207 case (9 >< 8) ^tm : word2 208 of 0b00w => w2w imm8 209 | 0b01w => if imm8 = 0w then ARB else 210 word32 [imm8; 0b00000000w; imm8; 0b00000000w] 211 | 0b10w => if imm8 = 0w then ARB else 212 word32 [0b00000000w; imm8; 0b00000000w; imm8] 213 | 0b11w => if imm8 = 0w then ARB else 214 word32 [imm8; imm8; imm8; imm8] 215 else 216 let unrotated_value = (7 :+ T) ((6 >< 0) ^tm) in 217 (unrotated_value #>> w2n ((11 -- 7) ^tm))`` 218 |> eval; 219 220fun shift tm = 221 comma ^ 222 (case uint_of_word tm 223 of 0 => "lsl " 224 | 1 => "lsr " 225 | 2 => "asr " 226 | 3 => "ror " 227 | _ => raise ERR "shift" "unexpected value"); 228 229fun disassemble_imm_shift (imm5,typ,rm) = 230 case uint_of_word typ 231 of 0 => if is_0 imm5 then 232 register rm 233 else 234 register rm ^ shift typ ^ constant imm5 235 | 1 => register rm ^ shift typ ^ 236 (if is_0 imm5 then "#32" else constant imm5) 237 | 2 => register rm ^ shift typ ^ 238 (if is_0 imm5 then "#32" else constant imm5) 239 | 3 => if is_0 imm5 then 240 register rm ^ comma ^ "rrx" 241 else 242 register rm ^ shift typ ^ constant imm5 243 | _ => raise ERR "disassemble_imm_shift" "unexpected value"; 244 245fun disassemble_mode1 thumb2 tm = 246 case dest_strip tm 247 of ("Mode1_immediate", [imm12]) => 248 imm12 |> (if thumb2 then thumb_expand_imm else arm_expand_imm) 249 |> constant 250 | ("Mode1_register", [imm5,typ,rm]) => 251 disassemble_imm_shift (imm5,typ,rm) 252 | ("Mode1_register_shifted_register", [rs,typ,rm]) => 253 register rm ^ shift typ ^ register rs 254 | _ => raise ERR "disassemble_mode1" ""; 255 256fun disassemble_mode2 (u,tm) = 257 case dest_strip tm 258 of ("Mode2_immediate", [imm12]) => 259 if is_T u andalso is_0 imm12 then 260 "" 261 else 262 comma ^ sign_constant (u,imm12) 263 | ("Mode2_register", [imm5,typ,rm]) => 264 comma ^ (if is_F u then "-" else "") ^ 265 disassemble_imm_shift (imm5,typ,rm) 266 | _ => raise ERR "disassemble_mode2" ""; 267 268fun disassemble_mode3 (u,tm) = 269 case dest_strip tm 270 of ("Mode3_immediate", [imm12]) => 271 if is_T u andalso is_0 imm12 then 272 "" 273 else 274 comma ^ sign_constant (u,imm12) 275 | ("Mode3_register", [imm2,rm]) => 276 comma ^ (if is_F u then "-" else "") ^ 277 disassemble_imm_shift (imm2,``0w:word2``,rm) 278 | _ => raise ERR "disassemble_mode3" ""; 279 280fun disassemble_mode5 (rn,p,u,w,imm8) = 281let val imm32 = ``((w2w ^imm8) << 2) : word32`` |> eval in 282 if is_T p then 283 opt (is_T w) "!" (square 284 (if is_0 imm32 then 285 register rn 286 else 287 commy [register rn, sign_constant (u,imm32)])) 288 else if is_T w then 289 commy [square (register rn), sign_constant (u,imm32)] 290 else if is_T u then 291 commy [square (register rn), curly (number imm8)] 292 else 293 raise ERR "disassemble_mode5" "unexpected mode" 294end; 295 296fun rotation (n,rot) = 297 case uint_of_word rot 298 of 0 => register n 299 | 1 => commy [register n, "ror #8"] 300 | 2 => commy [register n, "ror #16"] 301 | 3 => commy [register n, "ror #24"] 302 | _ => raise ERR "rotation" "unexpected value"; 303 304fun data_processing 305 (f : string -> string -> string * string) enc (opc,s,n,d,mode1) = 306let 307 val m1 = disassemble_mode1 (enc = Encoding_Thumb2_tm) mode1 308 val sflag = opt (is_T s) "s" 309 fun arith x = f (sflag x) (commy [register d, register n, m1]) 310 fun move x = f (sflag x) (commy [register d, m1]) 311 fun test x = f x (commy [register n, m1]) 312in 313 case uint_of_word opc 314 of 0 => arith "and" 315 | 1 => arith "eor" 316 | 2 => arith "sub" 317 | 3 => arith "rsb" 318 | 4 => arith "add" 319 | 5 => arith "adc" 320 | 6 => arith "sbc" 321 | 7 => arith "rsc" 322 | 8 => test "tst" 323 | 9 => test "teq" 324 | 10 => test "cmp" 325 | 11 => test "cmn" 326 | 12 => arith "orr" 327 | 13 => move "mov" 328 | 14 => arith "bic" 329 | 15 => if enc = Encoding_Thumb2_tm andalso not (is_PC n) then 330 arith "orn" 331 else 332 move "mvn" 333 | _ => raise ERR "register" "unexpected value" 334end; 335 336fun signed_halfword_multiply 337 (f : string -> string -> string * string) (opc,M,N,d,a,m,n) = 338 case (uint_of_word opc,is_T M,is_T N) 339 of (0,false,false) => f "smlabb" (rcommy [d,n,m,a]) 340 | (0,false,true ) => f "smlatb" (rcommy [d,n,m,a]) 341 | (0,true, false) => f "smlabt" (rcommy [d,n,m,a]) 342 | (0,true, true ) => f "smlatt" (rcommy [d,n,m,a]) 343 | (1,false,false) => f "smlawb" (rcommy [d,n,m,a]) 344 | (1,false,true) => f "smulwb" (rcommy [d,n,m]) 345 | (1,true, false) => f "smlawt" (rcommy [d,n,m,a]) 346 | (1,true, true) => f "smulwt" (rcommy [d,n,m]) 347 | (2,false,false) => f "smlalbb" (rcommy [d,n,m,a]) 348 | (2,false,true ) => f "smlaltb" (rcommy [d,n,m,a]) 349 | (2,true, false) => f "smlalbt" (rcommy [d,n,m,a]) 350 | (2,true, true ) => f "smlaltt" (rcommy [d,n,m,a]) 351 | (3,false,false) => f "smulbb" (rcommy [d,n,m]) 352 | (3,false,true ) => f "smultb" (rcommy [d,n,m]) 353 | (3,true, false) => f "smulbt" (rcommy [d,n,m]) 354 | (3,true, true ) => f "smultt" (rcommy [d,n,m]) 355 | _ => raise ERR "signed_halfword_multiply" "unexpected value"; 356 357fun parallel_add_subtract (u,(opc1,opc2)) = 358 case (is_T u,fst (dest_const opc1),fst (dest_const opc2)) 359 of (false,"Parallel_normal", "Parallel_add_16") => "sadd16" 360 | (false,"Parallel_normal", "Parallel_add_sub_exchange") => "sasx" 361 | (false,"Parallel_normal", "Parallel_sub_add_exchange") => "ssax" 362 | (false,"Parallel_normal", "Parallel_sub_16") => "ssub16" 363 | (false,"Parallel_normal", "Parallel_add_8") => "sadd8" 364 | (false,"Parallel_normal", "Parallel_sub_8") => "ssub8" 365 | (false,"Parallel_saturating", "Parallel_add_16") => "qadd16" 366 | (false,"Parallel_saturating", "Parallel_add_sub_exchange") => "qasx" 367 | (false,"Parallel_saturating", "Parallel_sub_add_exchange") => "qsax" 368 | (false,"Parallel_saturating", "Parallel_sub_16") => "qsub16" 369 | (false,"Parallel_saturating", "Parallel_add_8") => "qadd8" 370 | (false,"Parallel_saturating", "Parallel_sub_8") => "qsub8" 371 | (false,"Parallel_halving", "Parallel_add_16") => "shadd16" 372 | (false,"Parallel_halving", "Parallel_add_sub_exchange") => "shasx" 373 | (false,"Parallel_halving", "Parallel_sub_add_exchange") => "shsax" 374 | (false,"Parallel_halving", "Parallel_sub_16") => "shsub16" 375 | (false,"Parallel_halving", "Parallel_add_8") => "shadd8" 376 | (false,"Parallel_halving", "Parallel_sub_8") => "shsub8" 377 | (true, "Parallel_normal", "Parallel_add_16") => "uadd16" 378 | (true, "Parallel_normal", "Parallel_add_sub_exchange") => "uasx" 379 | (true, "Parallel_normal", "Parallel_sub_add_exchange") => "usax" 380 | (true, "Parallel_normal", "Parallel_sub_16") => "usub16" 381 | (true, "Parallel_normal", "Parallel_add_8") => "uadd8" 382 | (true, "Parallel_normal", "Parallel_sub_8") => "usub8" 383 | (true, "Parallel_saturating", "Parallel_add_16") => "uqadd16" 384 | (true, "Parallel_saturating", "Parallel_add_sub_exchange") => "uqasx" 385 | (true, "Parallel_saturating", "Parallel_sub_add_exchange") => "uqsax" 386 | (true, "Parallel_saturating", "Parallel_sub_16") => "uqsub16" 387 | (true, "Parallel_saturating", "Parallel_add_8") => "uqadd8" 388 | (true, "Parallel_saturating", "Parallel_sub_8") => "uqsub8" 389 | (true, "Parallel_halving", "Parallel_add_16") => "uhadd16" 390 | (true, "Parallel_halving", "Parallel_add_sub_exchange") => "uhasx" 391 | (true, "Parallel_halving", "Parallel_sub_add_exchange") => "uhsax" 392 | (true, "Parallel_halving", "Parallel_sub_16") => "uhsub16" 393 | (true, "Parallel_halving", "Parallel_add_8") => "uhadd8" 394 | (true, "Parallel_halving", "Parallel_sub_8") => "uhsub8" 395 | _ => raise ERR "parallel_add_subtract" "unexpected value"; 396 397fun msr_mask (r,mask) = 398let fun odd n = n mod 2 = 1 399 fun divodd n = (n div 2, odd n) 400 val n = uint_of_word mask 401 val (n,b0) = divodd n 402 val (n,b1) = divodd n 403 val (n,b2) = divodd n 404 val b3 = odd n 405in 406 String.concat ((if is_T r then "spsr_" else "cpsr_"):: 407 (List.map (fn (b,c) => opt b c "") [(b3,"f"),(b2,"s"),(b1,"x"),(b0,"c")])) 408end; 409 410fun it_mask c0 mask = 411let val n = uint_of_word mask in 412 if c0 then 413 case n 414 of 8 => "" 415 | 12 => "t" 416 | 4 => "e" 417 | 14 => "tt" 418 | 6 => "et" 419 | 10 => "te" 420 | 2 => "ee" 421 | 15 => "ttt" 422 | 7 => "ett" 423 | 11 => "tet" 424 | 3 => "eet" 425 | 13 => "tte" 426 | 5 => "ete" 427 | 9 => "tee" 428 | 1 => "eee" 429 | _ => raise ERR "it_mask" "" 430 else 431 case n 432 of 8 => "" 433 | 4 => "t" 434 | 12 => "e" 435 | 2 => "tt" 436 | 10 => "et" 437 | 6 => "te" 438 | 14 => "ee" 439 | 1 => "ttt" 440 | 9 => "ett" 441 | 5 => "tet" 442 | 13 => "eet" 443 | 3 => "tte" 444 | 11 => "ete" 445 | 7 => "tee" 446 | 15 => "eee" 447 | _ => raise ERR "it_mask" "" 448end; 449 450fun address f (p,u:term,w,n,t,mode:term) = 451 opt (is_T w andalso is_T p) "!" 452 (commy [register t, 453 (if is_T p then 454 [register n, f (u,mode)] |> String.concat |> square 455 else 456 String.concat [square (register n), f (u,mode)])]); 457 458fun indexing (p,u) = 459 (if is_T u then "i" else "d") ^ 460 (if is_T p then "b" else "a"); 461 462fun exclusive (n,imm8) = 463 square 464 (if is_0 imm8 then 465 register n 466 else 467 commy [register n, ``(w2w ^imm8 << 2) : word32`` |> eval |> constant]); 468 469fun hint (f : string -> string -> string * string) tm = 470 case dest_strip tm 471 of ("Hint_nop", []) => f "nop" "" 472 | ("Hint_yield", []) => f "yield" "" 473 | ("Hint_wait_for_event", []) => f "wfe" "" 474 | ("Hint_wait_for_interrupt", []) => f "wfi" "" 475 | ("Hint_send_event", []) => f "sev" "" 476 | ("Hint_debug", [opt]) => f "dbg" (constant opt) 477 | _ => raise ERR "hint" ""; 478 479fun barrier_option tm = 480 case uint_of_word tm 481 of 2 => "oshst" 482 | 3 => "osh" 483 | 6 => "nshst" 484 | 7 => "nsh" 485 | 10 => "ishst" 486 | 11 => "ish" 487 | 14 => "st" 488 | _ => "sy"; 489 490(* ------------------------------------------------------------------------- *) 491 492fun disassemble_branch (instr as (enc,_,tm)) = 493let val f = mnemonic instr in 494 case dest_strip (dest_Branch tm) 495 of ("Branch_Target", [imm24]) => 496 f "b" (``if ^enc = Encoding_ARM then 497 sw2sw ^imm24 << 2 + 8w : word32 498 else 499 sw2sw ^imm24 << 1 + 4w`` |> offset) 500 | ("Branch_Exchange", [m]) => 501 f "bx" (register m) 502 | ("Branch_Link_Exchange_Immediate", [h,toarm,imm24]) => 503 f (if (enc = Encoding_ARM_tm) = is_F toarm then "blx" else "bl") 504 (``let imm32 = (sw2sw ^imm24 << 2) + 505 (if ^enc = Encoding_ARM then 8w else 4w:word32) in 506 if ^toarm then imm32 else (1 :+ ^h) imm32`` |> offset) 507 | ("Branch_Link_Exchange_Register", [m]) => 508 f "blx" (register m) 509 | ("Compare_Branch", [nzero,imm6,n]) => 510 f (if is_T nzero then "cbnz" else "cbz") 511 (commy [register n, ``(w2w ^imm6 << 1) + 4w : word32`` |> offset]) 512 | ("Table_Branch_Byte", [n,h,m]) => 513 if is_T h then 514 f "tbh" (scommy [register n, register m, "lsl #1"]) 515 else 516 f "tbb" (scommy [register n, register m]) 517 | ("Check_Array", [n,m]) => 518 f "chka" (commy [register n,register m]) 519 | ("Handler_Branch_Link", [l,handler]) => 520 f (if is_T l then "hbl" else "hb") (constant handler) 521 | ("Handler_Branch_Link_Parameter", [imm5,handler]) => 522 f "hblp" (commy [constant imm5, constant handler]) 523 | ("Handler_Branch_Parameter", [imm3,handler]) => 524 f "hbp" (commy [constant imm3, constant handler]) 525 | _ => raise ERR "disassemble_branch" 526 ("cannot disassemble: " ^ term_to_string tm) 527end; 528 529fun disassemble_data_processing (instr as (enc,_,tm)) = 530let val f = mnemonic instr 531 fun ocommy b l x = rcommy (if b then l @ [x] else l) 532in 533 case dest_strip (dest_DataProcessing tm) 534 of ("Data_Processing", [opc,s,n,d,mode1]) => 535 data_processing f enc (opc,s,n,d,mode1) 536 | ("Move_Halfword", [h,d,imm16]) => 537 f (if is_T h then "movt" else "movw") 538 (commy [register d, constant imm16]) 539 | ("Add_Sub", [a,n,d,imm12]) => 540 if enc = Encoding_ARM_tm then 541 f (if is_T a then "add" else "sub") 542 (commy [register d, register n, 543 disassemble_mode1 false (mk_Mode1_immediate imm12)]) 544 else 545 f (if enc = Encoding_Thumb_tm then "add" else 546 if is_T a then "addw" else "subw") 547 (commy [register d, register n, constant imm12]) 548 | ("Multiply", [acc,s,d,a,m,n]) => 549 f ((if is_T acc then "mla" else "mul") ^ (if is_T s then "s" else "")) 550 (ocommy (is_T acc) [d,n,m] a) 551 | ("Multiply_Subtract", [d,a,m,n]) => 552 f "mls" (rcommy [d,n,m,a]) 553 | ("Signed_Halfword_Multiply", [opc,M,N,d,a,m,n]) => 554 signed_halfword_multiply f (opc,M,N,d,a,m,n) 555 | ("Signed_Multiply_Dual", [d,a,m,M,N,n]) => 556 f ((if is_T M 557 then if is_PC a then "smusd" else "smlsd" 558 else if is_PC a then "smuad" else "smlad") ^ 559 (if is_T N then "x" else "")) (ocommy (not (is_PC a)) [d,n,m] a) 560 | ("Signed_Multiply_Long_Dual", [dhi,dlo,m,M,N,n]) => 561 f ((if is_T M then "smlsld" else "smlald") ^ 562 (if is_T N then "x" else "")) (rcommy [dlo,dhi,n,m]) 563 | ("Signed_Most_Significant_Multiply", [d,a,m,r,n]) => 564 f ((if is_PC a then "smmul" else "smmla") ^ 565 (if is_T r then "r" else "")) (ocommy (not (is_PC a)) [d,n,m] a) 566 | ("Signed_Most_Significant_Multiply_Subtract", [d,a,m,r,n]) => 567 f (if is_T r then "smmlsr" else "smmls") (rcommy [d,n,m,a]) 568 | ("Multiply_Long", [sgnd,a,s,dhi,dlo,m,n]) => 569 f ((if is_T sgnd then "s" else "u") ^ 570 (if is_T a then "mlal" else "mull") ^ 571 (if is_T s then "s" else "")) (rcommy [dlo,dhi,n,m]) 572 | ("Multiply_Accumulate_Accumulate", [dhi,dlo,m,n]) => 573 f "umaal" (rcommy [dlo,dhi,n,m]) 574 | ("Saturate", [u,sat,d,imm5,sh,n]) => 575 let 576 val imm = constant (``if ^u then ^sat else ^sat + 1w`` |> eval) 577 val imm = if is_T u then imm else if imm = "#0" then "#32" else imm 578 in 579 f (if is_T u then "usat" else "ssat") 580 (commy [register d, imm, 581 disassemble_imm_shift 582 (imm5,mk_word2 (if is_T sh then 2 else 0),n)]) 583 end 584 | ("Saturate_16", [u,imm4,d,n]) => 585 let 586 val imm = constant (``if ^u then ^imm4 else ^imm4 + 1w`` |> eval) 587 val imm = if is_T u then imm else if imm = "#0" then "#16" else imm 588 in 589 f (if is_T u then "usat16" else "ssat16") 590 (commy [register d, imm, register n]) 591 end 592 | ("Saturating_Add_Subtract", [opc,n,d,m]) => 593 f (case uint_of_word opc 594 of 0 => "qadd" | 1 => "qsub" | 2 => "qdadd" | 3 => "qdsub" 595 | _ => raise ERR "disassemble_data_processing" "unexpected value") 596 (rcommy [d,m,n]) 597 | ("Pack_Halfword", [n,d,imm5,t,m]) => 598 f (if is_T t then "pkhtb" else "pkhbt") 599 (commy [register d, register n, 600 disassemble_imm_shift (imm5,mk_word2 (if is_T t then 2 else 0),m)]) 601 | ("Extend_Byte", [u,n,d,rot,m]) => 602 f ((if is_T u then "u" else "s") ^ 603 (if is_PC n then "xtb" else "xtab")) 604 (if is_PC n then 605 commy [register d, rotation (m,rot)] 606 else 607 commy [register d, register n, rotation (m,rot)]) 608 | ("Extend_Byte_16", [u,n,d,rot,m]) => 609 f ((if is_T u then "u" else "s") ^ 610 (if is_PC n then "xtb16" else "xtab16")) 611 (if is_PC n then 612 commy [register d, rotation (m,rot)] 613 else 614 commy [register d, register n, rotation (m,rot)]) 615 | ("Extend_Halfword", [u,n,d,rot,m]) => 616 f ((if is_T u then "u" else "s") ^ 617 (if is_PC n then "xth" else "xtah")) 618 (if is_PC n then 619 commy [register d, rotation (m,rot)] 620 else 621 commy [register d, register n, rotation (m,rot)]) 622 | ("Bit_Field_Clear_Insert", [msb,d,lsb,n]) => 623 let 624 val width = constant (``^msb - ^lsb + 1w`` |> eval) 625 val width = if width = "#0" then "#32" else width 626 in 627 if is_PC n then 628 f "bfc" (commy [register d, constant lsb, width]) 629 else 630 f "bfi" 631 (commy [register d, register n, constant lsb, width]) 632 end 633 | ("Count_Leading_Zeroes", [d,m]) => 634 f "clz" (rcommy [d,m]) 635 | ("Reverse_Bits", [d,m]) => 636 f "rbit" (rcommy [d,m]) 637 | ("Byte_Reverse_Word", [d,m]) => 638 f "rev" (rcommy [d,m]) 639 | ("Byte_Reverse_Packed_Halfword", [d,m]) => 640 f "rev16" (rcommy [d,m]) 641 | ("Byte_Reverse_Signed_Halfword", [d,m]) => 642 f "revsh" (rcommy [d,m]) 643 | ("Bit_Field_Extract", [u,w,d,lsb,n]) => 644 let val width = ``^w + 1w`` |> eval in 645 f (if is_T u then "ubfx" else "sbfx") 646 (commy [register d, register n, constant lsb, constant width]) 647 end 648 | ("Select_Bytes", [n,d,m]) => 649 f "sel" (rcommy [d,n,m]) 650 | ("Unsigned_Sum_Absolute_Differences", [d,a,m,n]) => 651 f (if is_PC a then "usad8" else "usada8") 652 (ocommy (not (is_PC a)) [d,n,m] a) 653 | ("Parallel_Add_Subtract", [u,opc,n,d,m]) => 654 f (parallel_add_subtract (u,pairTheory.dest_pair opc)) (rcommy [d,n,m]) 655 | ("Divide", [u,n,d,m]) => 656 f (if is_T u then "udiv" else "sdiv") (rcommy [d,n,m]) 657 | _ => raise ERR "disassemble_data_processing" 658 ("cannot disassemble: " ^ term_to_string tm) 659end; 660 661fun disassemble_status_access (instr as (enc,_,tm)) = 662let val f = mnemonic instr in 663 case dest_strip (dest_StatusAccess tm) 664 of ("Status_to_Register", [r,d]) => 665 f "mrs" (commy [register d, if is_T r then "spsr" else "cpsr"]) 666 | ("Immediate_to_Status", [r,mask,imm12]) => 667 f "msr" (commy [msr_mask (r,mask), imm12 |> arm_expand_imm |> constant]) 668 | ("Register_to_Status", [r,mask,n]) => 669 f "msr" (commy [msr_mask (r,mask), register n]) 670 | ("Change_Processor_State", [imod,A,I,F,mode]) => 671 let val effect = case uint_of_word imod 672 of 0 => "" 673 | 2 => "ie" 674 | 3 => "id" 675 | _ => raise ERR "disassemble_status_access" 676 "unexpected value" 677 fun optc x c = opt (is_T x) c "" 678 val iflags = String.concat [optc A "a",optc I "i",optc F "f"] 679 in 680 f ("cps" ^ effect) 681 (if effect = "" then 682 constant (optionSyntax.dest_some mode) 683 else if optionSyntax.is_some mode then 684 commy [iflags, constant (optionSyntax.dest_some mode)] 685 else 686 iflags) 687 end 688 | ("Set_Endianness", [e]) => 689 f "setend" (if is_T e then "be" else "le") 690 | _ => raise ERR "disassemble_status_access" 691 ("cannot disassemble: " ^ term_to_string tm) 692end; 693 694fun disassemble_load_store (instr as (enc,_,tm)) = 695let val f = mnemonic instr in 696 case dest_strip (dest_LoadStore tm) 697 of ("Load", [p,u,b,w,unpriv,n,t,mode2]) => 698 f (opt (is_T unpriv) "t" (if is_T b then "ldrb" else "ldr")) 699 (address disassemble_mode2 (p,u,w,n,t,mode2)) 700 | ("Store", [p,u,b,w,unpriv,n,t,mode2]) => 701 f (opt (is_T unpriv) "t" (if is_T b then "strb" else "str")) 702 (address disassemble_mode2 (p,u,w,n,t,mode2)) 703 | ("Load_Halfword", [p,u,w,s,h,unpriv,n,t,mode3]) => 704 f (opt (is_T unpriv) "t" 705 (case (is_T s,is_T h) 706 of (false, true ) => "ldrh" 707 | (true, false) => "ldrsb" 708 | (true, true ) => "ldrsh" 709 | _ => raise ERR "disassemble_load_store" "unexpected value")) 710 (address disassemble_mode3 (p,u,w,n,t,mode3)) 711 | ("Store_Halfword", [p,u,w,unpriv,n,t,mode3]) => 712 f (if is_T unpriv then "strht" else "strh") 713 (address disassemble_mode3 (p,u,w,n,t,mode3)) 714 | ("Load_Dual", [p,u,w,n,t,t2,mode3]) => 715 f "ldrd" 716 (commy [register t, address disassemble_mode3 (p,u,w,n,t2,mode3)]) 717 | ("Store_Dual", [p,u,w,n,t,t2,mode3]) => 718 f "strd" 719 (commy [register t, address disassemble_mode3 (p,u,w,n,t2,mode3)]) 720 | ("Load_Multiple", [p,u,s,w,n,registers]) => 721 if is_F p andalso is_T u andalso is_T w andalso is_F s andalso is_SP n 722 then 723 f "pop" (register_list registers) 724 else 725 f ("ldm" ^ indexing (p,u)) 726 (commy [opt (is_T w) "!" (register n), 727 opt (is_T s) "^" (register_list registers)]) 728 | ("Store_Multiple", [p,u,s,w,n,registers]) => 729 if is_T p andalso is_F u andalso is_T w andalso is_F s andalso is_SP n 730 then 731 f "push" (register_list registers) 732 else 733 f ("stm" ^ indexing (p,u)) 734 (commy [opt (is_T w) "!" (register n), 735 opt (is_T s) "^" (register_list registers)]) 736 | ("Load_Exclusive", [n,t,imm8]) => 737 f "ldrex" (commy [register t, exclusive (n,imm8)]) 738 | ("Store_Exclusive", [n,d,t,imm8]) => 739 f "strex" (commy [register d, register t, exclusive (n,imm8)]) 740 | ("Load_Exclusive_Doubleword", [n,t,t2]) => 741 f "ldrexd" (commy [register t, register t2, square (register n)]) 742 | ("Store_Exclusive_Doubleword", [n,d,t,t2]) => 743 f "strexd" 744 (commy [register d, register t, register t2, square (register n)]) 745 | ("Load_Exclusive_Halfword", [n,t]) => 746 f "ldrexh" (commy [register t, square (register n)]) 747 | ("Store_Exclusive_Halfword", [n,d,t]) => 748 f "strexh" (commy [register d, register t, square (register n)]) 749 | ("Load_Exclusive_Byte", [n,t]) => 750 f "ldrexb" (commy [register t, square (register n)]) 751 | ("Store_Exclusive_Byte", [n,d,t]) => 752 f "strexb" (commy [register d, register t, square (register n)]) 753 | ("Store_Return_State", [p,u,w,mode]) => 754 f ("srs" ^ indexing (p,u)) 755 (commy [opt (is_T w) "!" (register SP), constant mode]) 756 | ("Return_From_Exception", [p,u,w,n]) => 757 f ("rfe" ^ indexing (p,u)) (opt (is_T w) "!" (register n)) 758 | _ => raise ERR "disassemble_load_store" 759 ("cannot disassemble: " ^ term_to_string tm) 760end; 761 762fun disassemble_miscellaneous (instr as (enc,_,tm)) = 763let val f = mnemonic instr in 764 case dest_strip (dest_Miscellaneous tm) 765 of ("Hint", [h]) => 766 hint f h 767 | ("Breakpoint", [imm16]) => 768 f "bkpt" (constant imm16) 769 | ("Data_Memory_Barrier", [opt]) => 770 f "dmb" (barrier_option opt) 771 | ("Data_Synchronization_Barrier", [opt]) => 772 f "dsb" (barrier_option opt) 773 | ("Instruction_Synchronization_Barrier", [opt]) => 774 f "isb" "sy" 775 | ("Swap", [b,n,t,t2]) => 776 f (opt (is_T b) "b" "swp") 777 (commy [register t, register t2, square (register n)]) 778 | ("Preload_Data", [u,r,n,mode2]) => 779 f (opt (is_T r) "w" "pld") 780 ([register n, disassemble_mode2 (u,mode2)] |> String.concat |> square) 781 | ("Preload_Instruction", [u,n,mode2]) => 782 f "pli" 783 ([register n, disassemble_mode2 (u,mode2)] |> String.concat |> square) 784 | ("Supervisor_Call", [imm24]) => 785 f "svc" (constant imm24) 786 | ("Secure_Monitor_Call", [imm4]) => 787 f "smc" (constant imm4) 788 | ("Enterx_Leavex", [is_enterx]) => 789 f (if is_T is_enterx then "enterx" else "leavex") "" 790 | ("Clear_Exclusive", []) => 791 f "clrex" "" 792 | ("If_Then", [firstcond,mask]) => 793 f ("it" ^ it_mask ((uint_of_word firstcond) mod 2 = 1) mask) 794 (full_condition firstcond) 795 | _ => raise ERR "disassemble_miscellaneous" 796 ("cannot encode: " ^ term_to_string tm) 797end; 798 799fun disassemble_coprocessor (instr as (enc,cond,tm)) = 800let val f = mnemonic instr 801 val v2 = opt (is_var cond orelse is_PC cond) "2" 802 fun ocommy b l x = commy (if b then l @ [x] else l) 803in 804 case dest_strip (dest_Coprocessor tm) 805 of ("Coprocessor_Load", [p,u,d,w,n,cd,coproc,imm8]) => 806 f (opt (is_T d) "l" (v2 "ldc")) 807 (commy [coprocessor coproc, cregister cd, 808 disassemble_mode5 (n,p,u,w,imm8)]) 809 | ("Coprocessor_Store", [p,u,d,w,n,cd,coproc,imm8]) => 810 f (opt (is_T d) "l" (v2 "stc")) 811 (commy [coprocessor coproc, cregister cd, 812 disassemble_mode5 (n,p,u,w,imm8)]) 813 | ("Coprocessor_Data_Processing", [opc1,n,d,coproc,opc2,m]) => 814 f (v2 "cdp") 815 (ocommy (not (is_0 opc2)) 816 [coprocessor coproc, constant opc1, cregister d, 817 cregister n, cregister m] (constant opc2)) 818 | ("Coprocessor_Transfer", [opc1,mrc,n,t,coproc,opc2,m]) => 819 f (v2 (if is_T mrc then "mrc" else "mcr")) 820 (ocommy (not (is_0 opc2)) 821 [coprocessor coproc, constant opc1, register t, 822 cregister n, cregister m] (constant opc2)) 823 | ("Coprocessor_Transfer_Two", [mrrc,t2,t,coproc,opc,m]) => 824 f (v2 (if is_T mrrc then "mrrc" else "mcrr")) 825 (commy [coprocessor coproc, constant opc, register t, 826 register t2, cregister m]) 827 | _ => raise ERR "disassemble_coprocessor" 828 ("cannot disassemble: " ^ term_to_string tm) 829end; 830 831(* ------------------------------------------------------------------------- *) 832 833fun disassemble_instruction (instr as (enc,cond,tm)) = 834 case dest_strip tm 835 of ("Branch", [i]) => 836 disassemble_branch instr 837 | ("DataProcessing", [i]) => 838 disassemble_data_processing instr 839 | ("StatusAccess", [i]) => 840 disassemble_status_access instr 841 | ("LoadStore", [i]) => 842 disassemble_load_store instr 843 | ("Miscellaneous", [i]) => 844 disassemble_miscellaneous instr 845 | ("Coprocessor", [i]) => 846 disassemble_coprocessor instr 847 | ("Undefined", []) => 848 (case fst (dest_const enc) 849 of "Encoding_ARM" => let val c = hex_of_word cond in 850 directive_line "word" ("0x" ^ c ^ "6000010") 851 end 852 | "Encoding_Thumb" => directive_line "short" "0xDE00" 853 | "Encoding_Thumb2" => directive_line "word" "0xF7F0A000" 854 | _ => raise ERR "" "unexpected value") 855 | _ => raise ERR "disassemble_instruction" ("cannot disassemble: " ^ 856 term_to_string (pairSyntax.mk_pair (enc,tm))); 857 858(* ------------------------------------------------------------------------- *) 859 860fun arm_disassemble (arm_parserLib.Ascii s) = disassemble_ascii s 861 | arm_disassemble (arm_parserLib.Byte l) = disassemble_byte l 862 | arm_disassemble (arm_parserLib.Short l) = disassemble_short l 863 | arm_disassemble (arm_parserLib.Word l) = disassemble_word l 864 | arm_disassemble (arm_parserLib.Instruction i) = disassemble_instruction i; 865 866(* 867val arm_disassemble_parse = 868 List.map (arm_disassemble o 869 (snd : Arbnum.num * arm_parserLib.arm_code -> arm_parserLib.arm_code)); 870 871val arm_disassemble_from_quote = 872 arm_disassemble_parse o fst o arm_parserLib.arm_parse_from_quote; 873 874val arm_disassemble_from_string = 875 arm_disassemble_parse o fst o arm_parserLib.arm_parse_from_string; 876 877val arm_disassemble_from_file = 878 arm_disassemble_parse o fst o arm_parserLib.arm_parse_from_file; 879*) 880 881end 882