├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src ├── code.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "addr2line" 5 | version = "0.11.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "cpp_demangle 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "gimli 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", 11 | "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 12 | "object 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", 13 | "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "adler32" 19 | version = "1.0.4" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | 22 | [[package]] 23 | name = "ansi_term" 24 | version = "0.11.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | dependencies = [ 27 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 28 | ] 29 | 30 | [[package]] 31 | name = "arrayvec" 32 | version = "0.5.1" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | 35 | [[package]] 36 | name = "atty" 37 | version = "0.2.14" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 43 | ] 44 | 45 | [[package]] 46 | name = "autocfg" 47 | version = "1.0.0" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | 50 | [[package]] 51 | name = "backtrace" 52 | version = "0.3.43" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 56 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 59 | ] 60 | 61 | [[package]] 62 | name = "backtrace-sys" 63 | version = "0.1.32" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | dependencies = [ 66 | "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 68 | ] 69 | 70 | [[package]] 71 | name = "bitflags" 72 | version = "1.2.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | 75 | [[package]] 76 | name = "byteorder" 77 | version = "1.3.2" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | 80 | [[package]] 81 | name = "capstone" 82 | version = "0.5.0" 83 | source = "git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5#5044ace8022b1651d1b7c93d41ad56993e0225f5" 84 | dependencies = [ 85 | "capstone-sys 0.9.1 (git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5)", 86 | ] 87 | 88 | [[package]] 89 | name = "capstone-sys" 90 | version = "0.9.1" 91 | source = "git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5#5044ace8022b1651d1b7c93d41ad56993e0225f5" 92 | dependencies = [ 93 | "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", 94 | ] 95 | 96 | [[package]] 97 | name = "cc" 98 | version = "1.0.50" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | 101 | [[package]] 102 | name = "cfg-if" 103 | version = "0.1.10" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | 106 | [[package]] 107 | name = "clap" 108 | version = "2.33.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | dependencies = [ 111 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 113 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 114 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 115 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 116 | "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 117 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 118 | ] 119 | 120 | [[package]] 121 | name = "cpp_demangle" 122 | version = "0.2.14" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | dependencies = [ 125 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 126 | "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 127 | ] 128 | 129 | [[package]] 130 | name = "crc32fast" 131 | version = "1.2.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | dependencies = [ 134 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 135 | ] 136 | 137 | [[package]] 138 | name = "dtoa" 139 | version = "0.4.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | 142 | [[package]] 143 | name = "failure" 144 | version = "0.1.6" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | dependencies = [ 147 | "backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", 148 | "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 149 | ] 150 | 151 | [[package]] 152 | name = "failure_derive" 153 | version = "0.1.6" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | dependencies = [ 156 | "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 157 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 158 | "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", 159 | "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 160 | ] 161 | 162 | [[package]] 163 | name = "fallible-iterator" 164 | version = "0.2.0" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | 167 | [[package]] 168 | name = "findpanics" 169 | version = "0.1.0" 170 | dependencies = [ 171 | "addr2line 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 172 | "capstone 0.5.0 (git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5)", 173 | "capstone-sys 0.9.1 (git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5)", 174 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 175 | "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 176 | "gimli 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", 177 | "home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 178 | "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 179 | "object 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", 180 | "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 181 | "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 182 | "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", 183 | ] 184 | 185 | [[package]] 186 | name = "flate2" 187 | version = "1.0.13" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | dependencies = [ 190 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 191 | "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 192 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 193 | "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 194 | ] 195 | 196 | [[package]] 197 | name = "gimli" 198 | version = "0.20.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | dependencies = [ 201 | "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 202 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 203 | "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 204 | "indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 205 | "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 206 | "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 207 | ] 208 | 209 | [[package]] 210 | name = "glob" 211 | version = "0.3.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | 214 | [[package]] 215 | name = "goblin" 216 | version = "0.1.3" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | dependencies = [ 219 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 220 | "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 221 | "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 222 | ] 223 | 224 | [[package]] 225 | name = "hermit-abi" 226 | version = "0.1.6" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | dependencies = [ 229 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 230 | ] 231 | 232 | [[package]] 233 | name = "home" 234 | version = "0.5.3" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | dependencies = [ 237 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 238 | ] 239 | 240 | [[package]] 241 | name = "indexmap" 242 | version = "1.3.1" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | dependencies = [ 245 | "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 246 | ] 247 | 248 | [[package]] 249 | name = "lazycell" 250 | version = "1.2.1" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | 253 | [[package]] 254 | name = "libc" 255 | version = "0.2.66" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | 258 | [[package]] 259 | name = "linked-hash-map" 260 | version = "0.5.2" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | 263 | [[package]] 264 | name = "log" 265 | version = "0.4.8" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | dependencies = [ 268 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 269 | ] 270 | 271 | [[package]] 272 | name = "memmap" 273 | version = "0.7.0" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | dependencies = [ 276 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 277 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 278 | ] 279 | 280 | [[package]] 281 | name = "miniz_oxide" 282 | version = "0.3.5" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | dependencies = [ 285 | "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 286 | ] 287 | 288 | [[package]] 289 | name = "object" 290 | version = "0.17.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | dependencies = [ 293 | "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 294 | "goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 295 | "parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", 296 | "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "target-lexicon 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 298 | "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 299 | ] 300 | 301 | [[package]] 302 | name = "parity-wasm" 303 | version = "0.41.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | 306 | [[package]] 307 | name = "plain" 308 | version = "0.2.3" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | 311 | [[package]] 312 | name = "proc-macro2" 313 | version = "1.0.8" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | dependencies = [ 316 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 317 | ] 318 | 319 | [[package]] 320 | name = "quote" 321 | version = "1.0.2" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | dependencies = [ 324 | "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 325 | ] 326 | 327 | [[package]] 328 | name = "rustc-demangle" 329 | version = "0.1.16" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | 332 | [[package]] 333 | name = "scroll" 334 | version = "0.10.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | dependencies = [ 337 | "scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 338 | ] 339 | 340 | [[package]] 341 | name = "scroll_derive" 342 | version = "0.10.1" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | dependencies = [ 345 | "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 346 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 347 | "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", 348 | ] 349 | 350 | [[package]] 351 | name = "serde" 352 | version = "1.0.104" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | 355 | [[package]] 356 | name = "serde_derive" 357 | version = "1.0.104" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | dependencies = [ 360 | "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", 363 | ] 364 | 365 | [[package]] 366 | name = "serde_yaml" 367 | version = "0.8.11" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | dependencies = [ 370 | "dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 371 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 372 | "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", 373 | "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 374 | ] 375 | 376 | [[package]] 377 | name = "smallvec" 378 | version = "1.2.0" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | 381 | [[package]] 382 | name = "stable_deref_trait" 383 | version = "1.1.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | 386 | [[package]] 387 | name = "strsim" 388 | version = "0.8.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | 391 | [[package]] 392 | name = "syn" 393 | version = "1.0.14" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | dependencies = [ 396 | "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 397 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 398 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 399 | ] 400 | 401 | [[package]] 402 | name = "synstructure" 403 | version = "0.12.3" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | dependencies = [ 406 | "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 407 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 408 | "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", 409 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 410 | ] 411 | 412 | [[package]] 413 | name = "target-lexicon" 414 | version = "0.10.0" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | 417 | [[package]] 418 | name = "textwrap" 419 | version = "0.11.0" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | dependencies = [ 422 | "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 423 | ] 424 | 425 | [[package]] 426 | name = "unicode-width" 427 | version = "0.1.7" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | 430 | [[package]] 431 | name = "unicode-xid" 432 | version = "0.2.0" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | 435 | [[package]] 436 | name = "uuid" 437 | version = "0.8.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | 440 | [[package]] 441 | name = "vec_map" 442 | version = "0.8.1" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | 445 | [[package]] 446 | name = "winapi" 447 | version = "0.3.8" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | dependencies = [ 450 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 451 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 452 | ] 453 | 454 | [[package]] 455 | name = "winapi-i686-pc-windows-gnu" 456 | version = "0.4.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | 459 | [[package]] 460 | name = "winapi-x86_64-pc-windows-gnu" 461 | version = "0.4.0" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | 464 | [[package]] 465 | name = "yaml-rust" 466 | version = "0.4.3" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | dependencies = [ 469 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 470 | ] 471 | 472 | [metadata] 473 | "checksum addr2line 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4e698660ed2d0f625c39bb877332b4269668720e330e2aa3d67bb1187a656a" 474 | "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" 475 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 476 | "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 477 | "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 478 | "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 479 | "checksum backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f" 480 | "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" 481 | "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 482 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 483 | "checksum capstone 0.5.0 (git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5)" = "" 484 | "checksum capstone-sys 0.9.1 (git+https://github.com/capstone-rust/capstone-rs.git?rev=5044ace8022b1651d1b7c93d41ad56993e0225f5)" = "" 485 | "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" 486 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 487 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 488 | "checksum cpp_demangle 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4115af6f575a7bc82c613e9e0ed7cc36a5e4fc3a8b54920dc0c820823a31a0d6" 489 | "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 490 | "checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" 491 | "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" 492 | "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" 493 | "checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 494 | "checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" 495 | "checksum gimli 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81dd6190aad0f05ddbbf3245c54ed14ca4aa6dd32f22312b70d8f168c3e3e633" 496 | "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 497 | "checksum goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da" 498 | "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" 499 | "checksum home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" 500 | "checksum indexmap 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" 501 | "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 502 | "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 503 | "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 504 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 505 | "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" 506 | "checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" 507 | "checksum object 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea44a4fd660ab0f38434934ca0212e90fbeaaee54126ef20a3451c30c95bafae" 508 | "checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" 509 | "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 510 | "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" 511 | "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 512 | "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 513 | "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" 514 | "checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" 515 | "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" 516 | "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" 517 | "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" 518 | "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" 519 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 520 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 521 | "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" 522 | "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" 523 | "checksum target-lexicon 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" 524 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 525 | "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 526 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 527 | "checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" 528 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 529 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 530 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 531 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 532 | "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" 533 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "findpanics" 3 | version = "0.1.0" 4 | authors = ["Philip Craig "] 5 | categories = ["development-tools::debugging"] 6 | description = "Find calls to panic functions in rust executables" 7 | edition = "2018" 8 | license = "Apache-2.0/MIT" 9 | readme = "README.md" 10 | repository = "https://github.com/philipc/findpanics" 11 | 12 | [dependencies] 13 | addr2line = "0.11" 14 | clap = "2" 15 | failure = "0.1" 16 | gimli = "0.20" 17 | home = "0.5" 18 | memmap = "0.7" 19 | object = "0.17" 20 | capstone = { git = "https://github.com/capstone-rust/capstone-rs.git", rev = "5044ace8022b1651d1b7c93d41ad56993e0225f5" } 21 | capstone-sys = { git = "https://github.com/capstone-rust/capstone-rs.git", rev = "5044ace8022b1651d1b7c93d41ad56993e0225f5" } 22 | serde = "1.0" 23 | serde_derive = "1.0" 24 | serde_yaml = "0.8" 25 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 The findpanics Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # findpanics - Find calls to panic functions in rust executables 2 | 3 | Use disassembly and DWARF debugging information to find calls to panic functions. 4 | Currently only tested on Linux. 5 | 6 | This tool is intended for auditing specific aspects of an executable. You will never avoid 7 | most panics in rust code, but avoiding panics in specific locations may be possible. 8 | 9 | ## Installing 10 | After installing [Rust](https://www.rust-lang.org/), run: 11 | ``` 12 | cargo install --git https://github.com/philipc/findpanics 13 | ``` 14 | 15 | ## Running 16 | 17 | Usage: `findpanics ` 18 | 19 | The current directory must be the top level of a crate. 20 | 21 | A whitelist of allowed panics is read from `findpanics.yaml` in the current directory. 22 | Currently this whitelist must be created manually. 23 | 24 | ## Example output 25 | 26 | ``` 27 | In function 45800 findpanics::main::ha119f0252f22d91f 28 | 29 | Call to 1bfe50 core::panicking::panic::hdf4baf73e8b6719e 30 | at 45acd core::option::{{impl}}::unwrap<&str> (/checkout/src/libcore/macros.rs:20) 31 | inlined at findpanics::main (src/main.rs:61) 32 | source: let path = matches.value_of(OPT_FILE).unwrap(); 33 | ``` 34 | 35 | ## License 36 | 37 | This software is licensed under either of 38 | 39 | * Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 40 | * MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or http://opensource.org/licenses/MIT) 41 | 42 | at your option. 43 | 44 | Unless you explicitly state otherwise, any contribution intentionally submitted 45 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 46 | dual licensed as above, without any additional terms or conditions. 47 | -------------------------------------------------------------------------------- /src/code.rs: -------------------------------------------------------------------------------- 1 | use capstone::arch::x86::X86OperandType; 2 | use capstone::arch::x86::X86Reg::*; 3 | use capstone::arch::ArchOperand; 4 | use capstone::{self, Arch, Capstone, Insn, InsnDetail, InsnGroupType, Mode}; 5 | use object::target_lexicon::Architecture; 6 | use object::{File, Object, ObjectSegment}; 7 | use std::convert::TryInto; 8 | 9 | #[derive(Debug)] 10 | pub(crate) struct Code<'code> { 11 | arch: Arch, 12 | mode: Mode, 13 | regions: Vec>, 14 | } 15 | 16 | #[derive(Debug)] 17 | struct Region<'code> { 18 | address: u64, 19 | code: &'code [u8], 20 | } 21 | 22 | #[derive(Debug)] 23 | struct Call { 24 | pub from: u64, 25 | pub to: u64, 26 | } 27 | 28 | impl<'code> Code<'code> { 29 | pub(crate) fn new(file: &File<'code>) -> Option { 30 | let (arch, mode) = match file.architecture() { 31 | Architecture::I386 => (Arch::X86, Mode::Mode32), 32 | Architecture::X86_64 => (Arch::X86, Mode::Mode64), 33 | _ => return None, 34 | }; 35 | let mut regions = Vec::new(); 36 | // TODO: handle object files (no segments) 37 | // TODO: handle relocations 38 | for segment in file.segments() { 39 | regions.push(Region { 40 | address: segment.address(), 41 | code: segment.data(), 42 | }); 43 | } 44 | Some(Code { 45 | arch, 46 | mode, 47 | regions, 48 | }) 49 | } 50 | 51 | pub(crate) fn calls(&self, begin: u64, end: u64, mut f: F) -> Option<()> 52 | where 53 | F: FnMut(u64, u64), 54 | { 55 | if let Some(range) = self.range(begin, end) { 56 | let mut cs = 57 | Capstone::new_raw(self.arch, self.mode, capstone::NO_EXTRA_MODE, None).ok()?; 58 | cs.set_detail(true).ok()?; 59 | for insn in cs.disasm_all(range, begin).ok()?.iter() { 60 | if let Some(call) = call(self, &cs, &insn) { 61 | f(call.from, call.to); 62 | } 63 | } 64 | } 65 | Some(()) 66 | } 67 | 68 | fn range(&self, begin: u64, end: u64) -> Option<&'code [u8]> { 69 | for region in &self.regions { 70 | if begin >= region.address && end <= region.address + region.code.len() as u64 { 71 | let begin = (begin - region.address) as usize; 72 | let end = (end - region.address) as usize; 73 | return Some(®ion.code[begin..end]); 74 | } 75 | } 76 | None 77 | } 78 | } 79 | 80 | fn call(code: &Code, cs: &Capstone, insn: &Insn) -> Option { 81 | match code.arch { 82 | Arch::X86 => call_x86(code, cs, insn), 83 | _ => None, 84 | } 85 | } 86 | 87 | fn call_x86(code: &Code, cs: &Capstone, insn: &Insn) -> Option { 88 | let detail = cs.insn_detail(insn).ok()?; 89 | if !is_call(&detail) { 90 | return None; 91 | } 92 | let arch_detail = detail.arch_detail(); 93 | for op in arch_detail.operands() { 94 | if let ArchOperand::X86Operand(op) = op { 95 | match op.op_type { 96 | X86OperandType::Imm(imm) => { 97 | return Some(Call { 98 | from: insn.address(), 99 | to: imm as u64, 100 | }); 101 | } 102 | X86OperandType::Mem(op) => { 103 | let base = op.base().0 as u32; 104 | if base == X86_REG_RIP || base == X86_REG_EIP { 105 | let from = insn.address(); 106 | let mem = (from + insn.bytes().len() as u64).wrapping_add(op.disp() as u64); 107 | if base == X86_REG_RIP { 108 | if let Some(range) = code.range(mem, mem + 8) { 109 | let to = u64::from_le_bytes(range.try_into().unwrap()); 110 | return Some(Call { from, to }); 111 | } 112 | } else { 113 | if let Some(range) = code.range(mem, mem + 8) { 114 | let to = u32::from_le_bytes(range.try_into().unwrap()) as u64; 115 | return Some(Call { from, to }); 116 | } 117 | } 118 | } 119 | } 120 | _ => { 121 | // TODO: can we do anything with indirect register calls? 122 | } 123 | } 124 | } 125 | } 126 | None 127 | } 128 | 129 | fn is_call(detail: &InsnDetail) -> bool { 130 | detail 131 | .groups() 132 | .any(|group| group.0 as u32 == InsnGroupType::CS_GRP_CALL) 133 | } 134 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use addr2line; 2 | #[macro_use] 3 | extern crate clap; 4 | #[macro_use] 5 | extern crate failure; 6 | use gimli; 7 | use home; 8 | use memmap; 9 | use object::{self, Object}; 10 | #[macro_use] 11 | extern crate serde_derive; 12 | use serde_yaml; 13 | 14 | use std::borrow::Cow; 15 | use std::cmp::Ordering; 16 | use std::collections::HashMap; 17 | use std::io::{self, BufRead}; 18 | use std::iter::FromIterator; 19 | use std::path::PathBuf; 20 | use std::{env, fs, mem}; 21 | 22 | mod code; 23 | 24 | #[derive(Debug, Fail)] 25 | enum Error { 26 | #[fail(display = "{}", reason)] 27 | FindPanics { reason: String }, 28 | #[fail(display = "Error parsing DWARF: {}", reason)] 29 | Dwarf { reason: gimli::Error }, 30 | #[fail(display = "Error parsing object file: {}", reason)] 31 | Object { reason: &'static str }, 32 | } 33 | 34 | impl From for Error { 35 | fn from(reason: String) -> Error { 36 | Error::FindPanics { reason } 37 | } 38 | } 39 | 40 | impl<'a> From<&'a str> for Error { 41 | fn from(reason: &'a str) -> Error { 42 | Error::FindPanics { 43 | reason: reason.into(), 44 | } 45 | } 46 | } 47 | 48 | type Result = std::result::Result; 49 | 50 | const OPT_FILE: &str = "FILE"; 51 | const OPT_TERSE: &str = "t"; 52 | const OPT_ALL: &str = "a"; 53 | 54 | fn main() { 55 | let matches = clap::App::new("findpanics") 56 | .version(crate_version!()) 57 | .setting(clap::AppSettings::UnifiedHelpMessage) 58 | .arg( 59 | clap::Arg::with_name(OPT_FILE) 60 | .help("Path of file to print") 61 | .required(true) 62 | .index(1), 63 | ) 64 | .arg( 65 | clap::Arg::with_name(OPT_ALL) 66 | .short("a") 67 | .help("Show all, including libstd"), 68 | ) 69 | .arg( 70 | clap::Arg::with_name(OPT_TERSE) 71 | .short("t") 72 | .help("Terser output for diffing (no addresses or paths)"), 73 | ) 74 | .get_matches(); 75 | 76 | let path = matches.value_of(OPT_FILE).unwrap(); 77 | let all = matches.is_present(OPT_ALL); 78 | let terse = matches.is_present(OPT_TERSE); 79 | if let Err(e) = process_file(path, all, terse) { 80 | eprintln!("{}: {}", path, e); 81 | } 82 | } 83 | 84 | fn process_file(path: &str, all: bool, terse: bool) -> Result<()> { 85 | let cwd = env::current_dir() 86 | .map_err(|e| Error::from(format!("could not determine current dir: {}", e)))?; 87 | let cargo_home = home::cargo_home_with_cwd(&cwd) 88 | .map_err(|e| Error::from(format!("could not determine cargo dir: {}", e)))?; 89 | 90 | let handle = fs::File::open(path).map_err(|e| Error::from(format!("open failed: {}", e)))?; 91 | let map = unsafe { memmap::Mmap::map(&handle) } 92 | .map_err(|e| Error::from(format!("memmap failed: {}", e)))?; 93 | 94 | let object = object::File::parse(&*map).map_err(|reason| Error::Object { reason })?; 95 | let symbolizer = Symbolizer::new(&object)?; 96 | let disassembler = code::Code::new(&object).ok_or(Error::from("unsupported architecture"))?; 97 | let mut source_lines = SourceLines::default(); 98 | 99 | let mut config = match fs::File::open("findpanics.yaml") { 100 | Ok(f) => serde_yaml::from_reader(f) 101 | .map_err(|e| Error::from(format!("read findpanics.yaml failed: {}", e)))?, 102 | Err(_) => Config::default(), 103 | }; 104 | // TODO: validate whitelist source matches source obtained from `source_lines` 105 | config.whitelist.sort(); 106 | 107 | // Build list of symbols. 108 | let mut symbols: Vec = symbolizer 109 | .symbols 110 | .symbols() 111 | .iter() 112 | .filter_map(|symbol| { 113 | if symbol.kind() != object::SymbolKind::Text { 114 | return None; 115 | } 116 | let name = symbol.name().expect("symbols must have names"); 117 | let name = addr2line::demangle_auto(name.into(), None); 118 | let std = is_std_symbol(&name); 119 | let whitelist = is_whitelist_symbol(&name, std); 120 | Some(Symbol { 121 | name, 122 | std, 123 | whitelist, 124 | panic: false, 125 | address: symbol.address(), 126 | size: symbol.size(), 127 | succ: Vec::new(), 128 | pred: Vec::new(), 129 | }) 130 | }) 131 | .collect(); 132 | symbols.sort_by(|a, b| a.name.cmp(&b.name)); 133 | 134 | // Map from address to symbol index. 135 | // We assume calls are always to the start of a symbol. 136 | let symbol_map: HashMap = 137 | HashMap::from_iter(symbols.iter().enumerate().map(|(i, s)| (s.address, i))); 138 | 139 | // Build lists of succ/pred. 140 | for i in 0..symbols.len() { 141 | let begin = symbols[i].address; 142 | let end = begin + symbols[i].size; 143 | let mut succ = Vec::new(); 144 | disassembler.calls(begin, end, |from, to| { 145 | if let Some(&to) = symbol_map.get(&to) { 146 | succ.push((from, to)); 147 | symbols[to].pred.push(i); 148 | } 149 | }); 150 | symbols[i].succ = succ; 151 | } 152 | 153 | /* 154 | // Check that std symbols aren't calling user symbols. 155 | // Commented out because it picks up things in crates used by std (e.g. backtrace). 156 | for symbol in &symbols { 157 | if symbol.std { 158 | for succ in &symbol.succ { 159 | let succ = &symbols[succ.1]; 160 | if !succ.std { 161 | println!("{} should be std (called by {})", succ.name, symbol.name); 162 | } 163 | } 164 | } 165 | } 166 | */ 167 | 168 | // Determine which std symbols can panic. 169 | let mut todo = Vec::new(); 170 | for (i, symbol) in symbols.iter().enumerate() { 171 | if is_panic_symbol(&symbol.name) { 172 | todo.push(i); 173 | } 174 | } 175 | let mut current = Vec::new(); 176 | while !todo.is_empty() { 177 | mem::swap(&mut current, &mut todo); 178 | for symbol in current.drain(..) { 179 | let symbol = &mut symbols[symbol]; 180 | if !symbol.panic && !symbol.whitelist { 181 | symbol.panic = true; 182 | if symbol.std { 183 | todo.extend_from_slice(&symbol.pred); 184 | } 185 | } 186 | } 187 | } 188 | 189 | // Finally, determine which user symbols can directly panic. 190 | let mut calls = Vec::new(); 191 | for symbol in &symbols { 192 | if !all && symbol.std { 193 | continue; 194 | } 195 | if symbol.whitelist { 196 | continue; 197 | } 198 | 199 | calls.clear(); 200 | for &(from, to) in &symbol.succ { 201 | let to = &symbols[to]; 202 | if !to.panic || !to.std { 203 | continue; 204 | } 205 | let mut frames = Vec::new(); 206 | symbolizer.frames(from, |mut frame| { 207 | if let Some(ref path) = frame.path { 208 | frame.file = Some( 209 | path.strip_prefix(&cwd) 210 | .or_else(|_| path.strip_prefix(&cargo_home)) 211 | .unwrap_or(&path) 212 | .to_string_lossy() 213 | .into_owned(), 214 | ); 215 | } 216 | frames.push(frame) 217 | }); 218 | if !config.whitelist_matches(&frames, &to.name) { 219 | calls.push((from, to, frames)); 220 | } 221 | } 222 | 223 | if !calls.is_empty() { 224 | print!("In function "); 225 | if !terse { 226 | print!("{:x} ", symbol.address); 227 | } 228 | println!("{}", symbol.name); 229 | for &(from, to, ref frames) in &calls { 230 | println!(); 231 | 232 | print!(" Call to "); 233 | if !terse { 234 | print!("{:x} ", to.address); 235 | } 236 | println!("{}", to.name); 237 | 238 | print!(" at "); 239 | if !terse { 240 | print!("{:x} ", from); 241 | } 242 | let mut first = true; 243 | for frame in frames { 244 | if !first { 245 | print!(" inlined at "); 246 | } 247 | if let Some(ref function) = frame.function { 248 | print!("{}", function); 249 | } else { 250 | print!(""); 251 | } 252 | if !terse { 253 | if let Some(ref file) = frame.file { 254 | print!(" ({}:{}", file, frame.line); 255 | if frame.column != 0 { 256 | print!(":{}", frame.column); 257 | } 258 | print!(")"); 259 | } 260 | } 261 | println!(); 262 | if let Some(source) = frame 263 | .path 264 | .as_ref() 265 | .and_then(|path| source_lines.line(path, frame.line)) 266 | { 267 | println!(" source: {}", source); 268 | } 269 | first = false; 270 | } 271 | if first { 272 | println!(""); 273 | } 274 | } 275 | println!(); 276 | } 277 | } 278 | 279 | Ok(()) 280 | } 281 | 282 | fn is_panic_symbol(name: &str) -> bool { 283 | // TODO: how do we know this is enough? 284 | name == "core::panicking::panic" 285 | } 286 | 287 | fn is_std_symbol(mut name: &str) -> bool { 288 | if name.starts_with('<') { 289 | name = &name[1..]; 290 | } 291 | 292 | false 293 | || name.starts_with("alloc::") 294 | || name.starts_with("core::") 295 | || name.starts_with("std::") 296 | || name.starts_with("std_unicode::") 297 | || name.starts_with("rustc_demangle::") 298 | || name.starts_with("__rust_") 299 | || name.starts_with("str as core::") 300 | || name.starts_with("char as core::") 301 | || name.starts_with("&T as core::") 302 | || name == "rust_begin_unwind" 303 | || name == "rust_oom" 304 | || name == "rust_panic" 305 | } 306 | 307 | // functions for which panics are not interesting. 308 | fn is_whitelist_symbol(name: &str, std: bool) -> bool { 309 | // std-only whitelist 310 | std && (false 311 | || name == "alloc::fmt::format" 312 | || name == "core::fmt::write" 313 | || name == "std::io::Write::write_all" 314 | || name == "core::ptr::real_drop_in_place" 315 | || name == "alloc::raw_vec::capacity_overflow" 316 | || name == "std::rt::lang_start_internal" 317 | || name.ends_with("::fmt")) 318 | // std+user whitelist 319 | || name.ends_with(" as core::fmt::Debug>::fmt") 320 | } 321 | 322 | struct Frame { 323 | function: Option, 324 | path: Option, 325 | file: Option, 326 | line: usize, 327 | column: usize, 328 | } 329 | 330 | #[derive(Debug, Eq, Serialize, Deserialize)] 331 | struct WhiteListFrame { 332 | from: String, 333 | to: String, 334 | // TODO: record if relative to cwd or cargo_home 335 | file: String, 336 | line: usize, 337 | source: Option, 338 | comment: String, 339 | } 340 | 341 | impl Ord for WhiteListFrame { 342 | fn cmp(&self, other: &WhiteListFrame) -> Ordering { 343 | self.from 344 | .cmp(&other.from) 345 | .then_with(|| self.to.cmp(&other.to)) 346 | .then_with(|| self.file.cmp(&other.file)) 347 | .then_with(|| self.line.cmp(&other.line)) 348 | .then_with(|| self.source.cmp(&other.source)) 349 | } 350 | } 351 | 352 | impl PartialOrd for WhiteListFrame { 353 | fn partial_cmp(&self, other: &WhiteListFrame) -> Option { 354 | Some(self.cmp(other)) 355 | } 356 | } 357 | 358 | impl PartialEq for WhiteListFrame { 359 | fn eq(&self, other: &WhiteListFrame) -> bool { 360 | self.from == other.from 361 | && self.to == other.to 362 | && self.file == other.file 363 | && self.line == other.line 364 | && self.source == other.source 365 | } 366 | } 367 | 368 | #[derive(Debug, Default, Serialize, Deserialize)] 369 | struct Config { 370 | whitelist: Vec, 371 | } 372 | 373 | impl Config { 374 | fn whitelist_matches(&self, frames: &[Frame], to: &str) -> bool { 375 | let mut to = Some(to); 376 | for frame in frames { 377 | if let (Some(from), Some(to), Some(file)) = 378 | (frame.function.as_ref(), to.as_ref(), frame.file.as_ref()) 379 | { 380 | if self 381 | .whitelist 382 | .binary_search_by(|whitelist| { 383 | whitelist 384 | .from 385 | .cmp(&from) 386 | .then_with(|| whitelist.to.as_str().cmp(to)) 387 | .then_with(|| whitelist.file.cmp(file)) 388 | .then_with(|| whitelist.line.cmp(&frame.line)) 389 | }) 390 | .is_ok() 391 | { 392 | return true; 393 | } 394 | } 395 | to = frame.function.as_ref().map(String::as_str); 396 | } 397 | false 398 | } 399 | } 400 | 401 | #[derive(Default)] 402 | struct SourceLines { 403 | map: HashMap>, 404 | } 405 | 406 | impl SourceLines { 407 | fn line(&mut self, path: &PathBuf, mut line: usize) -> Option<&str> { 408 | if line == 0 { 409 | return None; 410 | } 411 | line -= 1; 412 | 413 | self.map 414 | .entry(path.clone()) 415 | .or_insert_with(|| read_lines(path).unwrap_or_default()) 416 | .get(line) 417 | .map(|line| line.as_ref()) 418 | } 419 | } 420 | 421 | fn read_lines(path: &PathBuf) -> io::Result> { 422 | let f = fs::File::open(path)?; 423 | let r = io::BufReader::new(f); 424 | let mut lines = Vec::new(); 425 | for line in r.lines() { 426 | lines.push(String::from(line?.trim())); 427 | } 428 | Ok(lines) 429 | } 430 | 431 | struct Symbolizer<'a> { 432 | symbols: object::SymbolMap<'a>, 433 | dwarf: addr2line::ObjectContext, 434 | } 435 | 436 | impl<'a> Symbolizer<'a> { 437 | fn new(object: &object::File<'a>) -> Result { 438 | let symbols = object.symbol_map(); 439 | let dwarf = addr2line::Context::new(object).map_err(|reason| Error::Dwarf { reason })?; 440 | Ok(Symbolizer { symbols, dwarf }) 441 | } 442 | 443 | fn frames(&self, address: u64, mut f: F) 444 | where 445 | F: FnMut(Frame), 446 | { 447 | if let Ok(mut frames) = self.dwarf.find_frames(address) { 448 | while let Ok(Some(frame)) = frames.next() { 449 | let function = frame 450 | .function 451 | .as_ref() 452 | .and_then(|function| function.demangle().ok()) 453 | .map(Cow::into_owned); 454 | // Require both file and line. 455 | if let Some(addr2line::Location { 456 | file: Some(path), 457 | line: Some(line), 458 | column, 459 | }) = frame.location 460 | { 461 | let line = line as usize; 462 | let column = column.unwrap_or(0) as usize; 463 | f(Frame { 464 | function, 465 | path: Some(path.into()), 466 | file: None, 467 | line, 468 | column, 469 | }); 470 | } else { 471 | f(Frame { 472 | function, 473 | path: None, 474 | file: None, 475 | line: 0, 476 | column: 0, 477 | }); 478 | } 479 | } 480 | } 481 | } 482 | } 483 | 484 | #[derive(Debug)] 485 | struct Symbol<'a> { 486 | name: Cow<'a, str>, 487 | std: bool, 488 | whitelist: bool, 489 | panic: bool, 490 | address: u64, 491 | size: u64, 492 | pred: Vec, 493 | succ: Vec<(u64, usize)>, 494 | } 495 | --------------------------------------------------------------------------------