├── LICENSE ├── README.md ├── abc12.bt └── abc9.bt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Zack Huang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ark Bytecode (.abc) 010Editor Template 2 | 3 | 010Editor template for .abc (Open/HarmonyOS Ark Bytecode) files 4 | 5 | Note: this is NOT a disassembler for the bytecode, but a parser for the file format that contains the bytecode. (Think .dex vs Dalvik bytecode) 6 | 7 | For a disassembler, see [https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/README.md#disassembler-ark_disasm](https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/README.md#disassembler-ark_disasm). 8 | 9 | # Known issues 10 | - Parsing of `LiteralArray` can be flawed due to poor documentation. By the documentation (see `References` section for a link), a `LiteralArray` has two fields: `num_literals` which indicates the number of literals this `LiteralArray` contains (somehow the number must be divided by 2 to get the actual number), and `literals` which is an array of `Literal`. The `Literal` struct, as it turns out, follows a Tag-Value format, which means the first field is a tag determining how the second field should be interpreted. Unfortunately, the tags are not documented at all. I had to extract them from the source code, but I'm not 100% sure if I understood everything in the relevant code correctly, especially the `LiteralTag::ARRAY_*` tags, given that this is such a huge project. 11 | - Parsing of methods referred to by `MethodRegionIndex` is still problematic, so this part of code has been commented out. 12 | - Parsing of `Proto` and `MethodHandle` is not implemented yet. 13 | - Parsing of `LineNumberProgram` is flawed too, as the operands in a line number program are not handled at all, and as such a `0x0` operand would be misinterpreted as marking the end of the program. 14 | - Should be fixed already (if I was looking at the right place in the code!). Parsing of `Value` of `any` type is not implemented. The `Value` struct is used when a `Field`, in its `field_data`, has a `TaggedValue` with the tag `VALUE` (bit of a tongue twister). `Value` follows a Tag-Value format too (but the "tag" is indicated by a field named `type_idx` in `Field`), whose tag is - surprise surprise - poorly documented. Luckily, this time the code is simpler, except for the `0x0b` tag, which means the type of the value is `any`. I have no idea what this type means and how it should be interpreted. 15 | 16 | # References 17 | - [Official documentation for the .abc format](https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/docs/file_format.md) (Careful, a few things in it are not accurate or up-to-date) 18 | - `arkcompiler\runtime_core\libpandafile\literal_data_accessor.h` 19 | - `arkcompiler\ets_runtime\ecmascript\jspandafile\js_pandafile.cpp` 20 | - FieldTag: `arkcompiler\runtime_core\libpandafile\field_data_accessor.cpp` 21 | - LiteralTag: `arkcompiler\runtime_core\libpandafile\literal_data_accessor-inl.h` 22 | - [Official ABC static defect scanner](https://gitee.com/openharmony/arkcompiler_runtime_core/tree/master/libark_defect_scan_aux) 23 | 24 | # Changelog 25 | - 2024/7/27: Added support for abc version >= 12.0.1.0 26 | - 2024/9/28: Fixed size of `modulerecord_literalarrs`; better handling of `constant_pool` 27 | -------------------------------------------------------------------------------- /abc12.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v12.0.1 Binary Template 3 | // 4 | // File: abc12.bt 5 | // Authors: hx1997 6 | // Version: 1.2 7 | // Purpose: 010Editor template for .abc (Open/HarmonyOS Ark Bytecode) files 8 | // Category: Operating Systems 9 | // History: 10 | // 1.2 2024-09-28 hx1997: Fix size of modulerecord_literalarrs; better handling of constant_pool (thanks to @alviszh) 11 | // 1.1 2024-07-27 hx1997: Add support for abc version >=12.0.1.0 (thanks to @hfkai). For older versions see https://github.com/hx1997/ark-bytecode-010editor-template 12 | // 1.0 2024-06-21 hx1997: Initial release on Script Repository 13 | //------------------------------------------------ 14 | 15 | uint Align( uint value, uint alignment ) 16 | { 17 | return (value + (alignment - 1)) & ~(alignment - 1); 18 | } 19 | 20 | void FAlign( uint alignment ) 21 | { 22 | FSeek( Align( FTell(), alignment ) ); 23 | } 24 | 25 | typedef struct { 26 | ubyte val ; 27 | if(val > 0x7f) { 28 | ubyte val ; 29 | if (val > 0x7f) { 30 | ubyte val ; 31 | if(val > 0x7f) { 32 | ubyte val ; 33 | if(val > 0x7f) { 34 | ubyte val ; 35 | } 36 | } 37 | } 38 | } 39 | } uleb128 ; 40 | 41 | // get the actual uint value of the uleb128 42 | uint uleb128_value(uleb128 &u) { 43 | local uint result; 44 | local ubyte cur; 45 | 46 | result = u.val[0]; 47 | if(result > 0x7f) { 48 | cur = u.val[1]; 49 | result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); 50 | if(cur > 0x7f) { 51 | cur = u.val[2]; 52 | result |= (uint)(cur & 0x7f) << 14; 53 | if(cur > 0x7f) { 54 | cur = u.val[3]; 55 | result |= (uint)(cur & 0x7f) << 21; 56 | if(cur > 0x7f) { 57 | cur = u.val[4]; 58 | result |= (uint)cur << 28; 59 | } 60 | } 61 | } 62 | } 63 | 64 | return result; 65 | } 66 | 67 | // get the number of bytes taken by a uleb128 68 | uint uleb128_size(uleb128 &u) { 69 | local uint result; 70 | local ubyte cur; 71 | local uint size = 1; 72 | 73 | result = u.val[0]; 74 | if(result > 0x7f) { 75 | size = 2; 76 | cur = u.val[1]; 77 | result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); 78 | if(cur > 0x7f) { 79 | size = 3; 80 | cur = u.val[2]; 81 | result |= (uint)(cur & 0x7f) << 14; 82 | if(cur > 0x7f) { 83 | size = 4; 84 | cur = u.val[3]; 85 | result |= (uint)(cur & 0x7f) << 21; 86 | if(cur > 0x7f) { 87 | size = 5; 88 | cur = u.val[4]; 89 | result |= (uint)cur << 28; 90 | } 91 | } 92 | } 93 | } 94 | 95 | return size; 96 | } 97 | 98 | typedef struct uleb128 uleb128p1; 99 | 100 | int uleb128p1_value(uleb128 &u) { 101 | return (int)uleb128_value(u) - 1; 102 | } 103 | 104 | string ULeb128Read(uleb128 &u) { 105 | local string s; 106 | s = SPrintf(s, "0x%X", uleb128_value(u)); 107 | return s; 108 | } 109 | 110 | // sleb128 111 | typedef struct { 112 | ubyte val ; 113 | if(val > 0x7f) { 114 | ubyte val ; 115 | if (val > 0x7f) { 116 | ubyte val ; 117 | if(val > 0x7f) { 118 | ubyte val ; 119 | if(val > 0x7f) { 120 | ubyte val ; 121 | } 122 | } 123 | } 124 | } 125 | } sleb128 ; 126 | 127 | // get the actual uint value of the uleb128 128 | int sleb128_value(sleb128 &u) { 129 | local int result; 130 | local ubyte cur; 131 | 132 | result = u.val[0]; 133 | if(result <= 0x7f) { 134 | result = (result << 25) >> 25; 135 | } else { 136 | cur = u.val[1]; 137 | result = (result & 0x7f) | ((uint)(cur & 0x7f) << 7); 138 | if(cur <= 0x7f) { 139 | result = (result << 18) >> 18; 140 | } else { 141 | cur = u.val[2]; 142 | result |= (uint)(cur & 0x7f) << 14; 143 | if(cur <= 0x7f) { 144 | result = (result << 11) >> 11; 145 | } else { 146 | cur = u.val[3]; 147 | result |= (uint)(cur & 0x7f) << 21; 148 | if(cur <= 0x7f) { 149 | result = (result << 4) >> 4; 150 | } else { 151 | cur = u.val[4]; 152 | result |= (uint)cur << 28; 153 | } 154 | } 155 | } 156 | } 157 | 158 | return result; 159 | } 160 | 161 | string SLeb128Read(sleb128 &u) { 162 | local string s; 163 | s = SPrintf(s, "%i", sleb128_value(u)); 164 | return s; 165 | } 166 | 167 | typedef struct { 168 | uleb128 utf16_length ; 169 | string data ; 170 | } String ; 171 | 172 | typedef struct { 173 | char panda[5]; 174 | char padding[3]; 175 | 176 | if(Strcmp(panda, "PANDA") || padding[0] != 0 || padding[1] != 0 || padding[2] != 0) { 177 | PrintWarning("Invalid ABC file"); 178 | return -1; 179 | } 180 | } abc_magic ; 181 | 182 | string AbcMagicRead(abc_magic &m) { 183 | string s; 184 | SPrintf(s, "%s\\0\\0\\0", m.panda); 185 | return s; 186 | } 187 | 188 | typedef struct { 189 | abc_magic magic ; 190 | uint checksum ; 191 | uchar version[4] ; 192 | uint filesize ; 193 | uint foreign_off ; 194 | uint foreign_size ; 195 | uint num_classes ; 196 | uint class_idx_off ; 197 | uint num_lnps ; 198 | uint lnp_idx_off ; 199 | uint num_literalarrays ; 200 | uint literalarray_idx_off ; 201 | uint num_index_regions ; 202 | uint index_section_off ; 203 | FAlign(4); 204 | } Header ; 205 | 206 | int readHeaderItemSize(Header &item) { 207 | return 60; 208 | } 209 | 210 | typedef struct { 211 | uleb128 type_idx ; 212 | uleb128 handler_pc ; 213 | uleb128 code_size ; 214 | } CatchBlock; 215 | 216 | typedef struct { 217 | uleb128 start_pc ; 218 | uleb128 length ; 219 | uleb128 num_catches ; 220 | CatchBlock catch_blocks[uleb128_value(num_catches)] ; 221 | } TryBlock; 222 | 223 | typedef struct { 224 | uleb128 num_vregs ; 225 | uleb128 num_args ; 226 | uleb128 code_size ; 227 | uleb128 tries_size ; 228 | uchar instructions[uleb128_value(code_size)] ; 229 | TryBlock try_blocks[uleb128_value(tries_size)] ; 230 | } Code; 231 | 232 | typedef struct { 233 | uint name_off ; 234 | readStringAt(name_off); 235 | // size of value is fixed (32-bit), see `arkcompiler\runtime_core\libpandafile\annotation_data_accessor.cpp` 236 | uint value ; 237 | } AnnotationElement; 238 | 239 | typedef struct { 240 | ushort class_idx ; 241 | ushort count ; 242 | AnnotationElement elements[count] ; 243 | uchar element_types[count] ; 244 | } Annotation; 245 | 246 | typedef struct { 247 | uint count ; 248 | uint offsets[count] ; 249 | } AnnotationArray; 250 | 251 | typedef struct { 252 | uint count ; 253 | AnnotationArray annotations[count] ; 254 | } ParamAnnotations; 255 | 256 | typedef struct { 257 | uleb128 line_start ; 258 | uleb128 num_parameters ; 259 | uleb128 parameters[uleb128_value(num_parameters)] ; 260 | uleb128 constant_pool_size ; 261 | 262 | local uint64 offset = 0; 263 | while (offset < uleb128_value(constant_pool_size)) { 264 | uleb128 constant_pool ; 265 | offset += uleb128_size(constant_pool); 266 | } 267 | 268 | uleb128 line_number_program_idx ; 269 | } DebugInfo; 270 | 271 | void readCodeAt(uint offset) { 272 | local int64 pos; 273 | local int color; 274 | if (offset != 0) { 275 | color = GetBackColor(); 276 | pos = FTell(); 277 | FSeek(offset); 278 | SetBackColor(0x00a5ff); 279 | Code code_data ; 280 | FSeek(pos); 281 | SetBackColor(color); 282 | } 283 | } 284 | 285 | void readAnnotationAt(uint offset) { 286 | local int64 pos; 287 | local int color; 288 | if (offset != 0) { 289 | color = GetBackColor(); 290 | pos = FTell(); 291 | FSeek(offset); 292 | SetBackColor(0xf09020); 293 | Annotation annotation_data; 294 | FSeek(pos); 295 | SetBackColor(color); 296 | } 297 | } 298 | 299 | void readParamAnnotationsAt(uint offset) { 300 | local int64 pos; 301 | local int color; 302 | if (offset != 0) { 303 | color = GetBackColor(); 304 | pos = FTell(); 305 | FSeek(offset); 306 | SetBackColor(0xf09020); 307 | ParamAnnotations annotation_data; 308 | FSeek(pos); 309 | SetBackColor(color); 310 | } 311 | } 312 | 313 | void readDebugInfoAt(uint offset) { 314 | local int64 pos; 315 | local int color; 316 | if (offset != 0) { 317 | color = GetBackColor(); 318 | pos = FTell(); 319 | FSeek(offset); 320 | SetBackColor(0xc0c0c0); 321 | DebugInfo debug_info_data ; 322 | FSeek(pos); 323 | SetBackColor(color); 324 | } 325 | } 326 | 327 | typedef struct { 328 | uchar tag_value ; 329 | switch (tag_value) { 330 | case 0: // NOTHING 331 | break; 332 | case 1: // INTERFACES 333 | uleb128 num_interfaces ; 334 | ushort interfaces_idx[uleb128_value(num_interfaces)] ; 335 | break; 336 | case 2: // SOURCE_LANG 337 | uchar source_lang ; 338 | break; 339 | case 3: // RUNTIME_ANNOTATION 340 | uint runtime_annotation ; 341 | readAnnotationAt(runtime_annotation); 342 | break; 343 | case 4: // ANNOTATION 344 | uint annotation ; 345 | readAnnotationAt(annotation); 346 | break; 347 | case 5: // RUNTIME_TYPE_ANNOTATION 348 | uchar runtime_type_annotation ; 349 | readAnnotationAt(runtime_type_annotation); 350 | break; 351 | case 6: // TYPE_ANNOTATION 352 | uchar type_annotation ; 353 | readAnnotationAt(type_annotation); 354 | break; 355 | case 7: // SOURCE_FILE 356 | uchar source_file ; 357 | break; 358 | } 359 | } ClassTag; 360 | 361 | uint getFieldTypeByIdx(ushort type_idx) { 362 | local int i; 363 | local uint64 pos = FTell(); 364 | for (i = 0; i < abc_header.num_index_regions; i++) { 365 | if (pos < abc_region_idxs.region_headers[i].start_off || pos > abc_region_idxs.region_headers[i].end_off) 366 | continue; 367 | return abc_region_idxs.region_headers[i].class_idx.types[type_idx].field_type; 368 | } 369 | } 370 | 371 | void readFieldValue(uint field_type) { 372 | // arkcompiler\runtime_core\libpandafile\field_data_accessor.cpp 373 | if (field_type < 16) { 374 | switch (field_type) { 375 | case 0x0: // u1 376 | case 0x2: // u8 377 | case 0x1: // i8 378 | case 0x3: // i16 379 | case 0x4: // u16 380 | case 0x5: // i32 381 | case 0x6: // u32 382 | case 0x7: // f32 383 | case 0xb: // any, not sure if this is right 384 | uint value ; 385 | break; 386 | case 0x8: // f64 387 | case 0x9: // i64 388 | case 0xa: // u64 389 | uint offset; 390 | uint64 pos = FTell(); 391 | FSeek(offset); 392 | uint64 value ; 393 | FSeek(pos); 394 | break; 395 | } 396 | } else { 397 | uint value ; 398 | } 399 | } 400 | 401 | typedef struct (ushort type_idx) { 402 | uchar tag_value ; 403 | switch (tag_value) { 404 | case 0: // NOTHING 405 | break; 406 | case 1: // INT_VALUE 407 | sleb128 int_value ; 408 | break; 409 | case 2: // VALUE 410 | local uint field_type = getFieldTypeByIdx(type_idx); 411 | readFieldValue(field_type); 412 | break; 413 | case 3: // RUNTIME_ANNOTATIONS 414 | uint runtime_annotations ; 415 | readAnnotationAt(runtime_annotations); 416 | break; 417 | case 4: // ANNOTATIONS 418 | uint annotations ; 419 | readAnnotationAt(annotations); 420 | break; 421 | case 5: // RUNTIME_TYPE_ANNOTATION 422 | uint runtime_type_annotation ; 423 | readAnnotationAt(runtime_type_annotation); 424 | break; 425 | case 6: // TYPE_ANNOTATION 426 | uint type_annotation ; 427 | readAnnotationAt(type_annotation); 428 | break; 429 | } 430 | } FieldTag; 431 | 432 | typedef struct { 433 | uchar tag_value ; 434 | switch (tag_value) { 435 | case 0: // NOTHING 436 | break; 437 | case 1: // CODE 438 | uint code ; 439 | readCodeAt(code); 440 | break; 441 | case 2: // SOURCE_LANG 442 | uchar source_lang ; 443 | break; 444 | case 3: // RUNTIME_ANNOTATION 445 | uint runtime_annotation ; 446 | readAnnotationAt(runtime_annotation); 447 | break; 448 | case 4: // RUNTIME_PARAM_ANNOTATION 449 | uint runtime_param_annotation ; 450 | readParamAnnotationAt(runtime_param_annotation); 451 | break; 452 | case 5: // DEBUG_INFO 453 | uint debug_info ; 454 | readDebugInfoAt(debug_info); 455 | break; 456 | case 6: // ANNOTATIONS 457 | uint annotations ; 458 | readAnnotationAt(annotations); 459 | break; 460 | case 7: // PARAM_ANNOTATION 461 | uint param_annotation ; 462 | readParamAnnotationAt(runtime_param_annotation); 463 | break; 464 | case 8: // TYPE_ANNOTATION 465 | uint type_annotation ; 466 | readAnnotationAt(type_annotation); 467 | break; 468 | case 9: // RUNTIME_TYPE_ANNOTATION 469 | uint runtime_type_annotation ; 470 | readAnnotationAt(runtime_type_annotation); 471 | break; 472 | } 473 | } MethodTag; 474 | 475 | string getShortyTypeName(uchar shorty_nibble) { 476 | switch (shorty_nibble) { 477 | case 0x0: 478 | return "end"; 479 | case 0x1: 480 | return "void"; 481 | case 0x2: 482 | return "u1"; 483 | case 0x3: 484 | return "i8"; 485 | case 0x4: 486 | return "u8"; 487 | case 0x5: 488 | return "i16"; 489 | case 0x6: 490 | return "u16"; 491 | case 0x7: 492 | return "i32"; 493 | case 0x8: 494 | return "u32"; 495 | case 0x9: 496 | return "f32"; 497 | case 0xa: 498 | return "f64"; 499 | case 0xb: 500 | return "i64"; 501 | case 0xc: 502 | return "u64"; 503 | case 0xd: 504 | return "ref"; 505 | case 0xe: 506 | return "any"; 507 | } 508 | } 509 | 510 | uint parseShorty() { 511 | BitfieldDisablePadding(); 512 | // Note that the bitfields within each byte are interpreted right-to-left. For example, if you have "0xec 0xce", this is read as 0xc (u64), 0xe (any), 0xe (any), 0xc (u64) 513 | local uint num_bits = 4; 514 | local uint num_refs = 0; 515 | ushort shorty_returntype : 4 ; 516 | 517 | if (shorty_returntype == 0xd) { 518 | num_refs++; 519 | } 520 | 521 | ushort shorty_paramlist : 4 ; 522 | while (shorty_paramlist != 0) { 523 | num_bits = (num_bits + 4) % 16; 524 | if (shorty_paramlist == 0xd) { 525 | num_refs++; 526 | } 527 | 528 | ushort shorty_paramlist : 4 ; 529 | } 530 | num_bits = (num_bits + 4) % 16; 531 | 532 | if (num_bits != 0) { 533 | // `Shorty` elements appear in groups of 16 bits. Padding is required if the `Shorty` ends when a group hasn't reached 16 bits. 534 | local uint padding_size = 16 - num_bits; 535 | ushort : padding_size; 536 | } 537 | return num_refs; 538 | } 539 | 540 | typedef struct { 541 | local uint num_refs = parseShorty(); 542 | ushort reference_types[num_refs] ; 543 | } Proto; 544 | 545 | void readStringAt(uint offset) { 546 | local int64 pos; 547 | if (offset != 0) { 548 | pos = FTell(); 549 | FSeek(offset); 550 | String str ; 551 | FSeek(pos); 552 | } 553 | } 554 | 555 | typedef struct { 556 | ushort class_idx ; 557 | ushort type_idx ; 558 | uint name_off ; 559 | readStringAt(name_off); 560 | uleb128 access_flags ; 561 | FieldTag field_data(type_idx); 562 | while (field_data.tag_value != 0) { 563 | FieldTag field_data(type_idx); 564 | } 565 | 566 | if (str.data == "moduleRecordIdx") { 567 | modulerecord_literalarrs[class_idx] = field_data[0].value; 568 | } 569 | } Field; 570 | 571 | typedef struct { 572 | ushort class_idx ; 573 | ushort reserved ; 574 | uint name_off ; 575 | readStringAt(name_off); 576 | uleb128 access_flags ; 577 | MethodTag method_data; 578 | while (method_data.tag_value != 0) { 579 | MethodTag method_data; 580 | } 581 | } Method; 582 | 583 | typedef struct { 584 | String name ; 585 | uint super_class_off ; 586 | uleb128 access_flags ; 587 | uleb128 num_fields ; 588 | uleb128 num_methods ; 589 | ClassTag class_data; 590 | while (class_data.tag_value != 0) { 591 | ClassTag class_data; 592 | } 593 | Field fields[uleb128_value(num_fields)] ; 594 | Method methods[uleb128_value(num_methods)] ; 595 | } class_item; 596 | 597 | typedef struct { 598 | uchar insns; 599 | while (insns != 0) { // END_SEQUENCE opcode 600 | uchar insns; 601 | } 602 | } LineNumberProgram; 603 | 604 | typedef struct { 605 | uchar tag; 606 | switch (tag) { 607 | case 0x0: // shouldn't be here according to source code but... seems to work? 608 | uchar value; 609 | break; 610 | case 0x2: // LiteralTag::INTEGER 611 | case 0x17: // LiteralTag::LITERALBUFFERINDEX 612 | uint value; 613 | break; 614 | case 0x4: // LiteralTag::DOUBLE 615 | double value; 616 | break; 617 | case 0x1: // LiteralTag::BOOL 618 | uchar value; 619 | break; 620 | case 0x3: // LiteralTag::FLOAT 621 | float value; 622 | break; 623 | case 0x5: // LiteralTag::STRING 624 | uint value; 625 | readStringAt(value); 626 | break; 627 | case 0x6: // LiteralTag::METHOD 628 | case 0x7: // LiteralTag::GENERATORMETHOD 629 | case 0x18: // LiteralTag::LITERALARRAY 630 | case 0x16: // LiteralTag::ASYNCGENERATORMETHOD 631 | uint value; 632 | break; 633 | case 0x9: // LiteralTag::METHODAFFILIATE 634 | ushort value; 635 | break; 636 | case 0x19: // LiteralTag::BUILTINTYPEINDEX 637 | case 0x8: // LiteralTag::ACCESSOR 638 | case 0xff: // LiteralTag::NULLVALUE 639 | uchar value; 640 | break; 641 | case 0xa: // LiteralTag::ARRAY_U1 642 | case 0xb: // LiteralTag::ARRAY_U8 643 | uchar value; 644 | break; 645 | case 0xc: // LiteralTag::ARRAY_I8 646 | char value; 647 | break; 648 | case 0xd: // LiteralTag::ARRAY_U16 649 | ushort value; 650 | break; 651 | case 0xe: // LiteralTag::ARRAY_I16 652 | short value; 653 | break; 654 | case 0xf: // LiteralTag::ARRAY_U32 655 | uint value; 656 | break; 657 | case 0x10: // LiteralTag::ARRAY_I32 658 | int value; 659 | break; 660 | case 0x11: // LiteralTag::ARRAY_U64 661 | uint64 value; 662 | break; 663 | case 0x12: // LiteralTag::ARRAY_I64 664 | int64 value; 665 | break; 666 | case 0x13: // LiteralTag::ARRAY_F32 667 | float value; 668 | break; 669 | case 0x14: // LiteralTag::ARRAY_F64 670 | double value; 671 | break; 672 | case 0x15: // LiteralTag::ARRAY_STRING 673 | uint value; 674 | break; 675 | } 676 | } Literal; 677 | 678 | uint GetActualNumLiterals(uint num_literals) { 679 | local uint64 pos = FTell(); 680 | 681 | local int i; 682 | local uint actual_num_literals = 0; 683 | local uchar tag; 684 | for (i = 0; i < num_literals / 2; i++) { 685 | tag = ReadUByte(pos); 686 | pos++; 687 | switch (tag) { 688 | case 0x0: // shouldn't be here according to source code but... seems to work? 689 | pos += 1; 690 | actual_num_literals++; 691 | break; 692 | case 0x2: // LiteralTag::INTEGER 693 | case 0x17: // LiteralTag::LITERALBUFFERINDEX 694 | pos += 4; 695 | actual_num_literals++; 696 | break; 697 | case 0x4: // LiteralTag::DOUBLE 698 | pos += 8; 699 | actual_num_literals++; 700 | break; 701 | case 0x1: // LiteralTag::BOOL 702 | pos += 1; 703 | actual_num_literals++; 704 | break; 705 | case 0x3: // LiteralTag::FLOAT 706 | pos += 4; 707 | actual_num_literals++; 708 | break; 709 | case 0x5: // LiteralTag::STRING 710 | case 0x6: // LiteralTag::METHOD 711 | case 0x7: // LiteralTag::GENERATORMETHOD 712 | case 0x18: // LiteralTag::LITERALARRAY 713 | case 0x16: // LiteralTag::ASYNCGENERATORMETHOD 714 | pos += 4; 715 | actual_num_literals++; 716 | break; 717 | case 0x9: // LiteralTag::METHODAFFILIATE 718 | pos += 2; 719 | actual_num_literals++; 720 | break; 721 | case 0x19: // LiteralTag::BUILTINTYPEINDEX 722 | case 0x8: // LiteralTag::ACCESSOR 723 | case 0xff: // LiteralTag::NULLVALUE 724 | pos += 1; 725 | actual_num_literals++; 726 | break; 727 | case 0xa: // LiteralTag::ARRAY_U1 728 | case 0xb: // LiteralTag::ARRAY_U8 729 | case 0xc: // LiteralTag::ARRAY_I8 730 | pos += 1; 731 | actual_num_literals++; 732 | i = num_literals / 2; 733 | break; 734 | case 0xd: // LiteralTag::ARRAY_U16 735 | case 0xe: // LiteralTag::ARRAY_I16 736 | pos += 2; 737 | actual_num_literals++; 738 | i = num_literals / 2; 739 | break; 740 | case 0xf: // LiteralTag::ARRAY_U32 741 | case 0x10: // LiteralTag::ARRAY_I32 742 | pos += 4; 743 | actual_num_literals++; 744 | i = num_literals / 2; 745 | break; 746 | case 0x11: // LiteralTag::ARRAY_U64 747 | case 0x12: // LiteralTag::ARRAY_I64 748 | pos += 8; 749 | actual_num_literals++; 750 | i = num_literals / 2; 751 | break; 752 | case 0x13: // LiteralTag::ARRAY_F32 753 | pos += 4; 754 | actual_num_literals++; 755 | i = num_literals / 2; 756 | break; 757 | case 0x14: // LiteralTag::ARRAY_F64 758 | pos += 8; 759 | actual_num_literals++; 760 | i = num_literals / 2; 761 | break; 762 | case 0x15: // LiteralTag::ARRAY_STRING 763 | actual_num_literals++; 764 | i = num_literals / 2; 765 | break; 766 | default: // invalid tag 767 | i = num_literals / 2; 768 | break; 769 | } 770 | } 771 | return actual_num_literals; 772 | } 773 | 774 | int indexof(uint64 arr[], int arrlen, uint64 key) { 775 | local int i; 776 | for (i = 0; i < arrlen; i++) { 777 | if (arr[i] == key) { 778 | return i; 779 | } 780 | } 781 | return -1; 782 | } 783 | 784 | typedef struct { 785 | uint local_name_offset; 786 | readStringAt(local_name_offset); 787 | uint import_name_offset; 788 | readStringAt(import_name_offset); 789 | ushort module_request_idx; 790 | } RegularImport; 791 | 792 | typedef struct { 793 | uint local_name_offset; 794 | readStringAt(local_name_offset); 795 | ushort module_request_idx; 796 | } NamespaceImport; 797 | 798 | 799 | typedef struct { 800 | uint local_name_offset; 801 | readStringAt(local_name_offset); 802 | uint export_name_offset; 803 | readStringAt(export_name_offset); 804 | } LocalExport; 805 | 806 | 807 | typedef struct { 808 | uint export_name_offset; 809 | readStringAt(export_name_offset); 810 | uint import_name_offset; 811 | readStringAt(import_name_offset); 812 | ushort module_request_idx; 813 | } IndirectExport; 814 | 815 | 816 | typedef struct { 817 | ushort module_request_idx; 818 | } StarExport; 819 | 820 | typedef struct { 821 | uint num_literals ; 822 | 823 | local int idx = indexof(modulerecord_literalarrs, abc_region_idxs.region_headers.class_idx_size, startof(this)); 824 | if (idx == -1) { 825 | // Actual number of literals is `num_literals / 2` if no `LiteralTag::ARRAY_*` types are present. 826 | // If any of these types is present, the actual number stops at the first occurrence (i.e., no more literals once a `LiteralTag::ARRAY_*` type is encountered), no matter what `num_literals / 2` is. 827 | // I don't know why this is so designed, see source code at `arkcompiler\runtime_core\libpandafile\literal_data_accessor-inl.h` 828 | local uint actual_num_literals = GetActualNumLiterals(num_literals); 829 | Literal literals[actual_num_literals] ; 830 | } else { 831 | uint num_module_requests; 832 | local int i; 833 | for (i = 0; i < num_module_requests; i++) { 834 | uint module_requests; 835 | readStringAt(module_requests); 836 | } 837 | 838 | uint regular_import_num; 839 | for (i = 0; i < regular_import_num; i++) { 840 | RegularImport regular_imports; 841 | } 842 | 843 | uint namespace_import_num; 844 | for (i = 0; i < namespace_import_num; i++) { 845 | NamespaceImport namespace_imports; 846 | } 847 | 848 | uint local_export_num; 849 | for (i = 0; i < local_export_num; i++) { 850 | LocalExport local_exports; 851 | } 852 | 853 | uint indirect_export_num; 854 | for (i = 0; i < indirect_export_num; i++) { 855 | IndirectExport indirect_exports; 856 | } 857 | 858 | uint starExportNum; 859 | for (i = 0; i < starExportNum; i++) { 860 | StarExport star_exports; 861 | } 862 | } 863 | } LiteralArray; 864 | 865 | typedef struct { 866 | uint field_type 16 bytes, any offset in the range [0; sizeof(Header)) is invalid. FieldType encoding uses this fact to encode primitive types of the field in the low 4 bits. For non-primitive type the value is an offset to Class or to ForeignClass. In both cases FieldType is uint32_t.">; 867 | } FieldType; 868 | 869 | typedef struct { 870 | String name; 871 | } ForeignClass; 872 | 873 | typedef struct { 874 | ushort class_idx ; 875 | ushort type_idx ; 876 | uint name_off ; 877 | readStringAt(name_off); 878 | } ForeignField; 879 | 880 | typedef struct { 881 | ushort class_idx ; 882 | ushort proto_idx ; 883 | uint name_off ; 884 | readStringAt(name_off); 885 | uleb128 access_flags ; 886 | } ForeignMethod; 887 | 888 | typedef struct (uint offset, int size) { 889 | local uint64 pos = FTell(); 890 | FSeek(offset); 891 | SetBackColor(0xd060d0); 892 | FieldType types[size] ; 893 | FAlign(4); 894 | FSeek(pos); 895 | } ClassRegionIndex; 896 | 897 | typedef struct (uint offset, int size) { 898 | local uint64 pos = FTell(); 899 | FSeek(offset); 900 | SetBackColor(0xd060d0); 901 | uint offsets[size] ; 902 | FAlign(4); 903 | FSeek(pos); 904 | } MethodStringLiteralRegionIndex; 905 | 906 | typedef struct (uint offset, int size) { 907 | local uint64 pos = FTell(); 908 | FSeek(offset); 909 | SetBackColor(0xd060d0); 910 | uint offsets[size] ; 911 | FAlign(4); 912 | 913 | local int i; 914 | local uint foreign_start = abc_header.foreign_off; 915 | local uint foreign_end = foreign_start + abc_header.foreign_size; 916 | local uint field_addr; 917 | for (i = 0; i < size; i++) { 918 | field_addr = offsets[i]; 919 | FSeek(field_addr); 920 | if (foreign_start <= field_addr && field_addr < foreign_end) 921 | ForeignField abc_field_items ; 922 | else 923 | Field abc_field_items ; 924 | } 925 | 926 | FSeek(pos); 927 | } FieldRegionIndex; 928 | 929 | typedef struct (uint offset, int size) { 930 | local uint64 pos = FTell(); 931 | FSeek(offset); 932 | SetBackColor(0xd060d0); 933 | uint offsets[size] ; 934 | FAlign(4); 935 | 936 | local int i; 937 | local uint proto_addr; 938 | for (i = 0; i < size; i++) { 939 | proto_addr = offsets[i]; 940 | FSeek(proto_addr); 941 | Proto abc_proto_items ; 942 | } 943 | 944 | FSeek(pos); 945 | } ProtoRegionIndex; 946 | 947 | typedef struct { 948 | uint start_off ; 949 | uint end_off ; 950 | uint class_idx_size ; 951 | uint class_idx_off ; 952 | ClassRegionIndex class_idx(class_idx_off, class_idx_size) ; 953 | uint method_string_literal_region_idx_size ; 954 | uint method_string_literal_region_idx_off ; 955 | MethodStringLiteralRegionIndex method_string_literal_idx(method_string_literal_region_idx_off, method_string_literal_region_idx_size) ; 956 | uint reserved1 ; 957 | uint reserved2 ; 958 | uint reserved3 ; 959 | uint reserved4 ; 960 | FAlign(4); 961 | } RegionHeader; 962 | 963 | typedef struct (int size) { 964 | uint class_def[size] ; 965 | FAlign(4); 966 | local uint64 pos = FTell(); 967 | 968 | SetBackColor(cLtBlue); 969 | local int i; 970 | local uint foreign_start = abc_header.foreign_off; 971 | local uint foreign_end = foreign_start + abc_header.foreign_size; 972 | local uint class_addr; 973 | for (i = 0; i < size; i++) { 974 | class_addr = class_def[i]; 975 | FSeek(class_addr); 976 | if (foreign_start <= class_addr && class_addr < foreign_end) 977 | ForeignClass abc_class_items ; 978 | else 979 | class_item abc_class_items ; 980 | } 981 | FSeek(pos); 982 | } ClassIndex; 983 | 984 | typedef struct (int size) { 985 | uint offsets[size] ; 986 | FAlign(4); 987 | local uint64 pos = FTell(); 988 | 989 | SetBackColor(cLtRed); 990 | local uint i; 991 | local uint lnp_addr; 992 | for (i = 0; i < size; i++) { 993 | lnp_addr = offsets[i]; 994 | FSeek(lnp_addr); 995 | LineNumberProgram abc_line_num_programs ; 996 | } 997 | FSeek(pos); 998 | } LineNumberProgramIndex; 999 | 1000 | typedef struct (int size) { 1001 | uint offsets[size] ; 1002 | FAlign(4); 1003 | local uint64 pos = FTell(); 1004 | 1005 | SetBackColor(cLtAqua); 1006 | local uint i; 1007 | local uint literalarray_addr; 1008 | for (i = 0; i < size; i++) { 1009 | literalarray_addr = offsets[i]; 1010 | FSeek(literalarray_addr); 1011 | LiteralArray abc_literalarrays ; 1012 | } 1013 | FSeek(pos); 1014 | } LiteralArrayIndex; 1015 | 1016 | typedef struct (int size) { 1017 | SetBackColor(0xa030a0); 1018 | RegionHeader region_headers[size] ; 1019 | FAlign(4); 1020 | } RegionIndex; 1021 | 1022 | SetBackColor(cLtGreen); 1023 | Header abc_header ; 1024 | 1025 | FSeek(abc_header.index_section_off); 1026 | SetBackColor(0xa030a0); 1027 | RegionIndex abc_region_idxs(abc_header.num_index_regions) ; 1028 | 1029 | local uint64 modulerecord_literalarrs[abc_region_idxs.region_headers.class_idx_size]; // Keep track of module record offsets when we parse Field. 1030 | 1031 | FSeek(abc_header.class_idx_off); 1032 | SetBackColor(cDkBlue); 1033 | ClassIndex abc_class_idxs(abc_header.num_classes) ; 1034 | 1035 | FSeek(abc_header.lnp_idx_off); 1036 | SetBackColor(cDkRed); 1037 | LineNumberProgramIndex abc_line_num_program_idxs(abc_header.num_lnps) ; 1038 | 1039 | FSeek(abc_header.literalarray_idx_off); 1040 | SetBackColor(cDkAqua); 1041 | LiteralArrayIndex abc_literalarray_idxs(abc_header.num_literalarrays) ; 1042 | -------------------------------------------------------------------------------- /abc9.bt: -------------------------------------------------------------------------------- 1 | //------------------------------------------------ 2 | //--- 010 Editor v12.0.1 Binary Template 3 | // 4 | // File: abc.bt 5 | // Authors: hx1997 6 | // Version: 1.1 7 | // Purpose: 010Editor template for .abc (Open/HarmonyOS Ark Bytecode) files 8 | // Category: Operating Systems 9 | // History: 10 | // 1.1 2024-09-28 hx1997: Fix size of modulerecord_literalarrs; better handling of constant_pool (thanks to @alviszh) 11 | // 1.0 2024-06-21 hx1997: Initial release on Script Repository 12 | //------------------------------------------------ 13 | 14 | uint Align( uint value, uint alignment ) 15 | { 16 | return (value + (alignment - 1)) & ~(alignment - 1); 17 | } 18 | 19 | void FAlign( uint alignment ) 20 | { 21 | FSeek( Align( FTell(), alignment ) ); 22 | } 23 | 24 | typedef struct { 25 | ubyte val ; 26 | if(val > 0x7f) { 27 | ubyte val ; 28 | if (val > 0x7f) { 29 | ubyte val ; 30 | if(val > 0x7f) { 31 | ubyte val ; 32 | if(val > 0x7f) { 33 | ubyte val ; 34 | } 35 | } 36 | } 37 | } 38 | } uleb128 ; 39 | 40 | // get the actual uint value of the uleb128 41 | uint uleb128_value(uleb128 &u) { 42 | local uint result; 43 | local ubyte cur; 44 | 45 | result = u.val[0]; 46 | if(result > 0x7f) { 47 | cur = u.val[1]; 48 | result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); 49 | if(cur > 0x7f) { 50 | cur = u.val[2]; 51 | result |= (uint)(cur & 0x7f) << 14; 52 | if(cur > 0x7f) { 53 | cur = u.val[3]; 54 | result |= (uint)(cur & 0x7f) << 21; 55 | if(cur > 0x7f) { 56 | cur = u.val[4]; 57 | result |= (uint)cur << 28; 58 | } 59 | } 60 | } 61 | } 62 | 63 | return result; 64 | } 65 | 66 | // get the number of bytes taken by a uleb128 67 | uint uleb128_size(uleb128 &u) { 68 | local uint result; 69 | local ubyte cur; 70 | local uint size = 1; 71 | 72 | result = u.val[0]; 73 | if(result > 0x7f) { 74 | size = 2; 75 | cur = u.val[1]; 76 | result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); 77 | if(cur > 0x7f) { 78 | size = 3; 79 | cur = u.val[2]; 80 | result |= (uint)(cur & 0x7f) << 14; 81 | if(cur > 0x7f) { 82 | size = 4; 83 | cur = u.val[3]; 84 | result |= (uint)(cur & 0x7f) << 21; 85 | if(cur > 0x7f) { 86 | size = 5; 87 | cur = u.val[4]; 88 | result |= (uint)cur << 28; 89 | } 90 | } 91 | } 92 | } 93 | 94 | return size; 95 | } 96 | 97 | typedef struct uleb128 uleb128p1; 98 | 99 | int uleb128p1_value(uleb128 &u) { 100 | return (int)uleb128_value(u) - 1; 101 | } 102 | 103 | string ULeb128Read(uleb128 &u) { 104 | local string s; 105 | s = SPrintf(s, "0x%X", uleb128_value(u)); 106 | return s; 107 | } 108 | 109 | // sleb128 110 | typedef struct { 111 | ubyte val ; 112 | if(val > 0x7f) { 113 | ubyte val ; 114 | if (val > 0x7f) { 115 | ubyte val ; 116 | if(val > 0x7f) { 117 | ubyte val ; 118 | if(val > 0x7f) { 119 | ubyte val ; 120 | } 121 | } 122 | } 123 | } 124 | } sleb128 ; 125 | 126 | // get the actual uint value of the uleb128 127 | int sleb128_value(sleb128 &u) { 128 | local int result; 129 | local ubyte cur; 130 | 131 | result = u.val[0]; 132 | if(result <= 0x7f) { 133 | result = (result << 25) >> 25; 134 | } else { 135 | cur = u.val[1]; 136 | result = (result & 0x7f) | ((uint)(cur & 0x7f) << 7); 137 | if(cur <= 0x7f) { 138 | result = (result << 18) >> 18; 139 | } else { 140 | cur = u.val[2]; 141 | result |= (uint)(cur & 0x7f) << 14; 142 | if(cur <= 0x7f) { 143 | result = (result << 11) >> 11; 144 | } else { 145 | cur = u.val[3]; 146 | result |= (uint)(cur & 0x7f) << 21; 147 | if(cur <= 0x7f) { 148 | result = (result << 4) >> 4; 149 | } else { 150 | cur = u.val[4]; 151 | result |= (uint)cur << 28; 152 | } 153 | } 154 | } 155 | } 156 | 157 | return result; 158 | } 159 | 160 | string SLeb128Read(sleb128 &u) { 161 | local string s; 162 | s = SPrintf(s, "%i", sleb128_value(u)); 163 | return s; 164 | } 165 | 166 | typedef struct { 167 | uleb128 utf16_length ; 168 | string data ; 169 | } String ; 170 | 171 | typedef struct { 172 | char panda[5]; 173 | char padding[3]; 174 | 175 | if(Strcmp(panda, "PANDA") || padding[0] != 0 || padding[1] != 0 || padding[2] != 0) { 176 | PrintWarning("Invalid ABC file"); 177 | return -1; 178 | } 179 | } abc_magic ; 180 | 181 | string AbcMagicRead(abc_magic &m) { 182 | string s; 183 | SPrintf(s, "%s\\0\\0\\0", m.panda); 184 | return s; 185 | } 186 | 187 | typedef struct { 188 | abc_magic magic ; 189 | uint checksum ; 190 | uchar version[4] ; 191 | uint filesize ; 192 | uint foreign_off ; 193 | uint foreign_size ; 194 | uint num_classes ; 195 | uint class_idx_off ; 196 | uint num_lnps ; 197 | uint lnp_idx_off ; 198 | uint num_literalarrays ; 199 | uint literalarray_idx_off ; 200 | uint num_index_regions ; 201 | uint index_section_off ; 202 | FAlign(4); 203 | } Header ; 204 | 205 | int readHeaderItemSize(Header &item) { 206 | return 60; 207 | } 208 | 209 | typedef struct { 210 | uleb128 type_idx ; 211 | uleb128 handler_pc ; 212 | uleb128 code_size ; 213 | } CatchBlock; 214 | 215 | typedef struct { 216 | uleb128 start_pc ; 217 | uleb128 length ; 218 | uleb128 num_catches ; 219 | CatchBlock catch_blocks[uleb128_value(num_catches)] ; 220 | } TryBlock; 221 | 222 | typedef struct { 223 | uleb128 num_vregs ; 224 | uleb128 num_args ; 225 | uleb128 code_size ; 226 | uleb128 tries_size ; 227 | uchar instructions[uleb128_value(code_size)] ; 228 | TryBlock try_blocks[uleb128_value(tries_size)] ; 229 | } Code; 230 | 231 | typedef struct { 232 | uint name_off ; 233 | readStringAt(name_off); 234 | // size of value is fixed (32-bit), see `arkcompiler\runtime_core\libpandafile\annotation_data_accessor.cpp` 235 | uint value ; 236 | } AnnotationElement; 237 | 238 | typedef struct { 239 | ushort class_idx ; 240 | ushort count ; 241 | AnnotationElement elements[count] ; 242 | uchar element_types[count] ; 243 | } Annotation; 244 | 245 | typedef struct { 246 | uint count ; 247 | uint offsets[count] ; 248 | } AnnotationArray; 249 | 250 | typedef struct { 251 | uint count ; 252 | AnnotationArray annotations[count] ; 253 | } ParamAnnotations; 254 | 255 | typedef struct { 256 | uleb128 line_start ; 257 | uleb128 num_parameters ; 258 | uleb128 parameters[uleb128_value(num_parameters)] ; 259 | uleb128 constant_pool_size ; 260 | 261 | local uint64 offset = 0; 262 | while (offset < uleb128_value(constant_pool_size)) { 263 | uleb128 constant_pool ; 264 | offset += uleb128_size(constant_pool); 265 | } 266 | 267 | uleb128 line_number_program_idx ; 268 | } DebugInfo; 269 | 270 | void readCodeAt(uint offset) { 271 | local int64 pos; 272 | local int color; 273 | if (offset != 0) { 274 | color = GetBackColor(); 275 | pos = FTell(); 276 | FSeek(offset); 277 | SetBackColor(0x00a5ff); 278 | Code code_data ; 279 | FSeek(pos); 280 | SetBackColor(color); 281 | } 282 | } 283 | 284 | void readAnnotationAt(uint offset) { 285 | local int64 pos; 286 | local int color; 287 | if (offset != 0) { 288 | color = GetBackColor(); 289 | pos = FTell(); 290 | FSeek(offset); 291 | SetBackColor(0xf09020); 292 | Annotation annotation_data; 293 | FSeek(pos); 294 | SetBackColor(color); 295 | } 296 | } 297 | 298 | void readParamAnnotationsAt(uint offset) { 299 | local int64 pos; 300 | local int color; 301 | if (offset != 0) { 302 | color = GetBackColor(); 303 | pos = FTell(); 304 | FSeek(offset); 305 | SetBackColor(0xf09020); 306 | ParamAnnotations annotation_data; 307 | FSeek(pos); 308 | SetBackColor(color); 309 | } 310 | } 311 | 312 | void readDebugInfoAt(uint offset) { 313 | local int64 pos; 314 | local int color; 315 | if (offset != 0) { 316 | color = GetBackColor(); 317 | pos = FTell(); 318 | FSeek(offset); 319 | SetBackColor(0xc0c0c0); 320 | DebugInfo debug_info_data ; 321 | FSeek(pos); 322 | SetBackColor(color); 323 | } 324 | } 325 | 326 | typedef struct { 327 | uchar tag_value ; 328 | switch (tag_value) { 329 | case 0: // NOTHING 330 | break; 331 | case 1: // INTERFACES 332 | uleb128 num_interfaces ; 333 | ushort interfaces_idx[uleb128_value(num_interfaces)] ; 334 | break; 335 | case 2: // SOURCE_LANG 336 | uchar source_lang ; 337 | break; 338 | case 3: // RUNTIME_ANNOTATION 339 | uint runtime_annotation ; 340 | readAnnotationAt(runtime_annotation); 341 | break; 342 | case 4: // ANNOTATION 343 | uint annotation ; 344 | readAnnotationAt(annotation); 345 | break; 346 | case 5: // RUNTIME_TYPE_ANNOTATION 347 | uchar runtime_type_annotation ; 348 | readAnnotationAt(runtime_type_annotation); 349 | break; 350 | case 6: // TYPE_ANNOTATION 351 | uchar type_annotation ; 352 | readAnnotationAt(type_annotation); 353 | break; 354 | case 7: // SOURCE_FILE 355 | uchar source_file ; 356 | break; 357 | } 358 | } ClassTag; 359 | 360 | uint getFieldTypeByIdx(ushort type_idx) { 361 | local int i; 362 | local uint64 pos = FTell(); 363 | for (i = 0; i < abc_header.num_index_regions; i++) { 364 | if (pos < abc_region_idxs.region_headers[i].start_off || pos > abc_region_idxs.region_headers[i].end_off) 365 | continue; 366 | return abc_region_idxs.region_headers[i].class_idx.types[type_idx].field_type; 367 | } 368 | } 369 | 370 | void readFieldValue(uint field_type) { 371 | // arkcompiler\runtime_core\libpandafile\field_data_accessor.cpp 372 | if (field_type < 16) { 373 | switch (field_type) { 374 | case 0x0: // u1 375 | case 0x2: // u8 376 | case 0x1: // i8 377 | case 0x3: // i16 378 | case 0x4: // u16 379 | case 0x5: // i32 380 | case 0x6: // u32 381 | case 0x7: // f32 382 | case 0xb: // any, not sure if this is right 383 | uint value ; 384 | break; 385 | case 0x8: // f64 386 | case 0x9: // i64 387 | case 0xa: // u64 388 | uint offset; 389 | uint64 pos = FTell(); 390 | FSeek(offset); 391 | uint64 value ; 392 | FSeek(pos); 393 | break; 394 | } 395 | } else { 396 | uint value ; 397 | } 398 | } 399 | 400 | typedef struct (ushort type_idx) { 401 | uchar tag_value ; 402 | switch (tag_value) { 403 | case 0: // NOTHING 404 | break; 405 | case 1: // INT_VALUE 406 | sleb128 int_value ; 407 | break; 408 | case 2: // VALUE 409 | local uint field_type = getFieldTypeByIdx(type_idx); 410 | readFieldValue(field_type); 411 | break; 412 | case 3: // RUNTIME_ANNOTATIONS 413 | uint runtime_annotations ; 414 | readAnnotationAt(runtime_annotations); 415 | break; 416 | case 4: // ANNOTATIONS 417 | uint annotations ; 418 | readAnnotationAt(annotations); 419 | break; 420 | case 5: // RUNTIME_TYPE_ANNOTATION 421 | uint runtime_type_annotation ; 422 | readAnnotationAt(runtime_type_annotation); 423 | break; 424 | case 6: // TYPE_ANNOTATION 425 | uint type_annotation ; 426 | readAnnotationAt(type_annotation); 427 | break; 428 | } 429 | } FieldTag; 430 | 431 | typedef struct { 432 | uchar tag_value ; 433 | switch (tag_value) { 434 | case 0: // NOTHING 435 | break; 436 | case 1: // CODE 437 | uint code ; 438 | readCodeAt(code); 439 | break; 440 | case 2: // SOURCE_LANG 441 | uchar source_lang ; 442 | break; 443 | case 3: // RUNTIME_ANNOTATION 444 | uint runtime_annotation ; 445 | readAnnotationAt(runtime_annotation); 446 | break; 447 | case 4: // RUNTIME_PARAM_ANNOTATION 448 | uint runtime_param_annotation ; 449 | readParamAnnotationAt(runtime_param_annotation); 450 | break; 451 | case 5: // DEBUG_INFO 452 | uint debug_info ; 453 | readDebugInfoAt(debug_info); 454 | break; 455 | case 6: // ANNOTATIONS 456 | uint annotations ; 457 | readAnnotationAt(annotations); 458 | break; 459 | case 7: // PARAM_ANNOTATION 460 | uint param_annotation ; 461 | readParamAnnotationAt(runtime_param_annotation); 462 | break; 463 | case 8: // TYPE_ANNOTATION 464 | uint type_annotation ; 465 | readAnnotationAt(type_annotation); 466 | break; 467 | case 9: // RUNTIME_TYPE_ANNOTATION 468 | uint runtime_type_annotation ; 469 | readAnnotationAt(runtime_type_annotation); 470 | break; 471 | } 472 | } MethodTag; 473 | 474 | string getShortyTypeName(uchar shorty_nibble) { 475 | switch (shorty_nibble) { 476 | case 0x0: 477 | return "end"; 478 | case 0x1: 479 | return "void"; 480 | case 0x2: 481 | return "u1"; 482 | case 0x3: 483 | return "i8"; 484 | case 0x4: 485 | return "u8"; 486 | case 0x5: 487 | return "i16"; 488 | case 0x6: 489 | return "u16"; 490 | case 0x7: 491 | return "i32"; 492 | case 0x8: 493 | return "u32"; 494 | case 0x9: 495 | return "f32"; 496 | case 0xa: 497 | return "f64"; 498 | case 0xb: 499 | return "i64"; 500 | case 0xc: 501 | return "u64"; 502 | case 0xd: 503 | return "ref"; 504 | case 0xe: 505 | return "any"; 506 | } 507 | } 508 | 509 | uint parseShorty() { 510 | BitfieldDisablePadding(); 511 | // Note that the bitfields within each byte are interpreted right-to-left. For example, if you have "0xec 0xce", this is read as 0xc (u64), 0xe (any), 0xe (any), 0xc (u64) 512 | local uint num_bits = 4; 513 | local uint num_refs = 0; 514 | ushort shorty_returntype : 4 ; 515 | 516 | if (shorty_returntype == 0xd) { 517 | num_refs++; 518 | } 519 | 520 | ushort shorty_paramlist : 4 ; 521 | while (shorty_paramlist != 0) { 522 | num_bits = (num_bits + 4) % 16; 523 | if (shorty_paramlist == 0xd) { 524 | num_refs++; 525 | } 526 | 527 | ushort shorty_paramlist : 4 ; 528 | } 529 | num_bits = (num_bits + 4) % 16; 530 | 531 | if (num_bits != 0) { 532 | // `Shorty` elements appear in groups of 16 bits. Padding is required if the `Shorty` ends when a group hasn't reached 16 bits. 533 | local uint padding_size = 16 - num_bits; 534 | ushort : padding_size; 535 | } 536 | return num_refs; 537 | } 538 | 539 | typedef struct { 540 | local uint num_refs = parseShorty(); 541 | ushort reference_types[num_refs] ; 542 | } Proto; 543 | 544 | void readStringAt(uint offset) { 545 | local int64 pos; 546 | if (offset != 0) { 547 | pos = FTell(); 548 | FSeek(offset); 549 | String str ; 550 | FSeek(pos); 551 | } 552 | } 553 | 554 | typedef struct { 555 | ushort class_idx ; 556 | ushort type_idx ; 557 | uint name_off ; 558 | readStringAt(name_off); 559 | uleb128 access_flags ; 560 | FieldTag field_data(type_idx); 561 | while (field_data.tag_value != 0) { 562 | FieldTag field_data(type_idx); 563 | } 564 | 565 | if (str.data == "moduleRecordIdx") { 566 | modulerecord_literalarrs[class_idx] = field_data[0].value; 567 | } 568 | } Field; 569 | 570 | typedef struct { 571 | ushort class_idx ; 572 | ushort proto_idx ; 573 | uint name_off ; 574 | readStringAt(name_off); 575 | uleb128 access_flags ; 576 | MethodTag method_data; 577 | while (method_data.tag_value != 0) { 578 | MethodTag method_data; 579 | } 580 | } Method; 581 | 582 | typedef struct { 583 | String name ; 584 | uint super_class_off ; 585 | uleb128 access_flags ; 586 | uleb128 num_fields ; 587 | uleb128 num_methods ; 588 | ClassTag class_data; 589 | while (class_data.tag_value != 0) { 590 | ClassTag class_data; 591 | } 592 | Field fields[uleb128_value(num_fields)] ; 593 | Method methods[uleb128_value(num_methods)] ; 594 | } class_item; 595 | 596 | typedef struct { 597 | uchar insns; 598 | while (insns != 0) { // END_SEQUENCE opcode 599 | uchar insns; 600 | } 601 | } LineNumberProgram; 602 | 603 | typedef struct { 604 | uchar tag; 605 | switch (tag) { 606 | case 0x0: // shouldn't be here according to source code but... seems to work? 607 | uchar value; 608 | break; 609 | case 0x2: // LiteralTag::INTEGER 610 | case 0x17: // LiteralTag::LITERALBUFFERINDEX 611 | uint value; 612 | break; 613 | case 0x4: // LiteralTag::DOUBLE 614 | double value; 615 | break; 616 | case 0x1: // LiteralTag::BOOL 617 | uchar value; 618 | break; 619 | case 0x3: // LiteralTag::FLOAT 620 | float value; 621 | break; 622 | case 0x5: // LiteralTag::STRING 623 | uint value; 624 | readStringAt(value); 625 | break; 626 | case 0x6: // LiteralTag::METHOD 627 | case 0x7: // LiteralTag::GENERATORMETHOD 628 | case 0x18: // LiteralTag::LITERALARRAY 629 | case 0x16: // LiteralTag::ASYNCGENERATORMETHOD 630 | uint value; 631 | break; 632 | case 0x9: // LiteralTag::METHODAFFILIATE 633 | ushort value; 634 | break; 635 | case 0x19: // LiteralTag::BUILTINTYPEINDEX 636 | case 0x8: // LiteralTag::ACCESSOR 637 | case 0xff: // LiteralTag::NULLVALUE 638 | uchar value; 639 | break; 640 | case 0xa: // LiteralTag::ARRAY_U1 641 | case 0xb: // LiteralTag::ARRAY_U8 642 | uchar value; 643 | break; 644 | case 0xc: // LiteralTag::ARRAY_I8 645 | char value; 646 | break; 647 | case 0xd: // LiteralTag::ARRAY_U16 648 | ushort value; 649 | break; 650 | case 0xe: // LiteralTag::ARRAY_I16 651 | short value; 652 | break; 653 | case 0xf: // LiteralTag::ARRAY_U32 654 | uint value; 655 | break; 656 | case 0x10: // LiteralTag::ARRAY_I32 657 | int value; 658 | break; 659 | case 0x11: // LiteralTag::ARRAY_U64 660 | uint64 value; 661 | break; 662 | case 0x12: // LiteralTag::ARRAY_I64 663 | int64 value; 664 | break; 665 | case 0x13: // LiteralTag::ARRAY_F32 666 | float value; 667 | break; 668 | case 0x14: // LiteralTag::ARRAY_F64 669 | double value; 670 | break; 671 | case 0x15: // LiteralTag::ARRAY_STRING 672 | uint value; 673 | break; 674 | } 675 | } Literal; 676 | 677 | uint GetActualNumLiterals(uint num_literals) { 678 | local uint64 pos = FTell(); 679 | 680 | local int i; 681 | local uint actual_num_literals = 0; 682 | local uchar tag; 683 | for (i = 0; i < num_literals / 2; i++) { 684 | tag = ReadUByte(pos); 685 | pos++; 686 | switch (tag) { 687 | case 0x0: // shouldn't be here according to source code but... seems to work? 688 | pos += 1; 689 | actual_num_literals++; 690 | break; 691 | case 0x2: // LiteralTag::INTEGER 692 | case 0x17: // LiteralTag::LITERALBUFFERINDEX 693 | pos += 4; 694 | actual_num_literals++; 695 | break; 696 | case 0x4: // LiteralTag::DOUBLE 697 | pos += 8; 698 | actual_num_literals++; 699 | break; 700 | case 0x1: // LiteralTag::BOOL 701 | pos += 1; 702 | actual_num_literals++; 703 | break; 704 | case 0x3: // LiteralTag::FLOAT 705 | pos += 4; 706 | actual_num_literals++; 707 | break; 708 | case 0x5: // LiteralTag::STRING 709 | case 0x6: // LiteralTag::METHOD 710 | case 0x7: // LiteralTag::GENERATORMETHOD 711 | case 0x18: // LiteralTag::LITERALARRAY 712 | case 0x16: // LiteralTag::ASYNCGENERATORMETHOD 713 | pos += 4; 714 | actual_num_literals++; 715 | break; 716 | case 0x9: // LiteralTag::METHODAFFILIATE 717 | pos += 2; 718 | actual_num_literals++; 719 | break; 720 | case 0x19: // LiteralTag::BUILTINTYPEINDEX 721 | case 0x8: // LiteralTag::ACCESSOR 722 | case 0xff: // LiteralTag::NULLVALUE 723 | pos += 1; 724 | actual_num_literals++; 725 | break; 726 | case 0xa: // LiteralTag::ARRAY_U1 727 | case 0xb: // LiteralTag::ARRAY_U8 728 | case 0xc: // LiteralTag::ARRAY_I8 729 | pos += 1; 730 | actual_num_literals++; 731 | i = num_literals / 2; 732 | break; 733 | case 0xd: // LiteralTag::ARRAY_U16 734 | case 0xe: // LiteralTag::ARRAY_I16 735 | pos += 2; 736 | actual_num_literals++; 737 | i = num_literals / 2; 738 | break; 739 | case 0xf: // LiteralTag::ARRAY_U32 740 | case 0x10: // LiteralTag::ARRAY_I32 741 | pos += 4; 742 | actual_num_literals++; 743 | i = num_literals / 2; 744 | break; 745 | case 0x11: // LiteralTag::ARRAY_U64 746 | case 0x12: // LiteralTag::ARRAY_I64 747 | pos += 8; 748 | actual_num_literals++; 749 | i = num_literals / 2; 750 | break; 751 | case 0x13: // LiteralTag::ARRAY_F32 752 | pos += 4; 753 | actual_num_literals++; 754 | i = num_literals / 2; 755 | break; 756 | case 0x14: // LiteralTag::ARRAY_F64 757 | pos += 8; 758 | actual_num_literals++; 759 | i = num_literals / 2; 760 | break; 761 | case 0x15: // LiteralTag::ARRAY_STRING 762 | actual_num_literals++; 763 | i = num_literals / 2; 764 | break; 765 | default: // invalid tag 766 | i = num_literals / 2; 767 | break; 768 | } 769 | } 770 | return actual_num_literals; 771 | } 772 | 773 | int indexof(uint64 arr[], int arrlen, uint64 key) { 774 | local int i; 775 | for (i = 0; i < arrlen; i++) { 776 | if (arr[i] == key) { 777 | return i; 778 | } 779 | } 780 | return -1; 781 | } 782 | 783 | typedef struct { 784 | uint local_name_offset; 785 | readStringAt(local_name_offset); 786 | uint import_name_offset; 787 | readStringAt(import_name_offset); 788 | ushort module_request_idx; 789 | } RegularImport; 790 | 791 | typedef struct { 792 | uint local_name_offset; 793 | readStringAt(local_name_offset); 794 | ushort module_request_idx; 795 | } NamespaceImport; 796 | 797 | 798 | typedef struct { 799 | uint local_name_offset; 800 | readStringAt(local_name_offset); 801 | uint export_name_offset; 802 | readStringAt(export_name_offset); 803 | } LocalExport; 804 | 805 | 806 | typedef struct { 807 | uint export_name_offset; 808 | readStringAt(export_name_offset); 809 | uint import_name_offset; 810 | readStringAt(import_name_offset); 811 | ushort module_request_idx; 812 | } IndirectExport; 813 | 814 | 815 | typedef struct { 816 | ushort module_request_idx; 817 | } StarExport; 818 | 819 | typedef struct { 820 | uint num_literals ; 821 | 822 | local int idx = indexof(modulerecord_literalarrs, abc_region_idxs.region_headers.class_idx_size, startof(this)); 823 | if (idx == -1) { 824 | // Actual number of literals is `num_literals / 2` if no `LiteralTag::ARRAY_*` types are present. 825 | // If any of these types is present, the actual number stops at the first occurrence (i.e., no more literals once a `LiteralTag::ARRAY_*` type is encountered), no matter what `num_literals / 2` is. 826 | // I don't know why this is so designed, see source code at `arkcompiler\runtime_core\libpandafile\literal_data_accessor-inl.h` 827 | local uint actual_num_literals = GetActualNumLiterals(num_literals); 828 | Literal literals[actual_num_literals] ; 829 | } else { 830 | uint num_module_requests; 831 | local int i; 832 | for (i = 0; i < num_module_requests; i++) { 833 | uint module_requests; 834 | readStringAt(module_requests); 835 | } 836 | 837 | uint regular_import_num; 838 | for (i = 0; i < regular_import_num; i++) { 839 | RegularImport regular_imports; 840 | } 841 | 842 | uint namespace_import_num; 843 | for (i = 0; i < namespace_import_num; i++) { 844 | NamespaceImport namespace_imports; 845 | } 846 | 847 | uint local_export_num; 848 | for (i = 0; i < local_export_num; i++) { 849 | LocalExport local_exports; 850 | } 851 | 852 | uint indirect_export_num; 853 | for (i = 0; i < indirect_export_num; i++) { 854 | IndirectExport indirect_exports; 855 | } 856 | 857 | uint starExportNum; 858 | for (i = 0; i < starExportNum; i++) { 859 | StarExport star_exports; 860 | } 861 | } 862 | } LiteralArray; 863 | 864 | typedef struct { 865 | uint field_type 16 bytes, any offset in the range [0; sizeof(Header)) is invalid. FieldType encoding uses this fact to encode primitive types of the field in the low 4 bits. For non-primitive type the value is an offset to Class or to ForeignClass. In both cases FieldType is uint32_t.">; 866 | } FieldType; 867 | 868 | typedef struct { 869 | String name; 870 | } ForeignClass; 871 | 872 | typedef struct { 873 | ushort class_idx ; 874 | ushort type_idx ; 875 | uint name_off ; 876 | readStringAt(name_off); 877 | } ForeignField; 878 | 879 | typedef struct { 880 | ushort class_idx ; 881 | ushort proto_idx ; 882 | uint name_off ; 883 | readStringAt(name_off); 884 | uleb128 access_flags ; 885 | } ForeignMethod; 886 | 887 | typedef struct (uint offset, int size) { 888 | local uint64 pos = FTell(); 889 | FSeek(offset); 890 | SetBackColor(0xd060d0); 891 | FieldType types[size] ; 892 | FAlign(4); 893 | FSeek(pos); 894 | } ClassRegionIndex; 895 | 896 | typedef struct (uint offset, int size) { 897 | local uint64 pos = FTell(); 898 | FSeek(offset); 899 | SetBackColor(0xd060d0); 900 | uint offsets[size] ; 901 | FAlign(4); 902 | 903 | //local int i; 904 | //local uint foreign_start = abc_header.foreign_off; 905 | //local uint foreign_end = foreign_start + abc_header.foreign_size; 906 | //local uint method_addr; 907 | //for (i = 0; i < size; i++) { 908 | // method_addr = offsets[i]; 909 | // FSeek(method_addr); 910 | // if (foreign_start <= method_addr && method_addr < foreign_end) 911 | // ForeignMethod abc_method_items ; 912 | // else 913 | // Method abc_method_items ; 914 | //} 915 | 916 | FSeek(pos); 917 | } MethodRegionIndex; 918 | 919 | typedef struct (uint offset, int size) { 920 | local uint64 pos = FTell(); 921 | FSeek(offset); 922 | SetBackColor(0xd060d0); 923 | uint offsets[size] ; 924 | FAlign(4); 925 | 926 | local int i; 927 | local uint foreign_start = abc_header.foreign_off; 928 | local uint foreign_end = foreign_start + abc_header.foreign_size; 929 | local uint field_addr; 930 | for (i = 0; i < size; i++) { 931 | field_addr = offsets[i]; 932 | FSeek(field_addr); 933 | if (foreign_start <= field_addr && field_addr < foreign_end) 934 | ForeignField abc_field_items ; 935 | else 936 | Field abc_field_items ; 937 | } 938 | 939 | FSeek(pos); 940 | } FieldRegionIndex; 941 | 942 | typedef struct (uint offset, int size) { 943 | local uint64 pos = FTell(); 944 | FSeek(offset); 945 | SetBackColor(0xd060d0); 946 | uint offsets[size] ; 947 | FAlign(4); 948 | 949 | local int i; 950 | local uint proto_addr; 951 | for (i = 0; i < size; i++) { 952 | proto_addr = offsets[i]; 953 | FSeek(proto_addr); 954 | Proto abc_proto_items ; 955 | } 956 | 957 | FSeek(pos); 958 | } ProtoRegionIndex; 959 | 960 | typedef struct { 961 | uint start_off ; 962 | uint end_off ; 963 | uint class_idx_size ; 964 | uint class_idx_off ; 965 | ClassRegionIndex class_idx(class_idx_off, class_idx_size) ; 966 | uint method_idx_size ; 967 | uint method_idx_off ; 968 | MethodRegionIndex method_idx(method_idx_off, method_idx_size) ; 969 | uint field_idx_size ; 970 | uint field_idx_off ; 971 | FieldRegionIndex field_idx(field_idx_off, field_idx_size) ; 972 | uint proto_idx_size ; 973 | uint proto_idx_off ; 974 | ProtoRegionIndex proto_idx(proto_idx_off, proto_idx_size) ; 975 | FAlign(4); 976 | } RegionHeader; 977 | 978 | typedef struct (int size) { 979 | uint class_def[size] ; 980 | FAlign(4); 981 | local uint64 pos = FTell(); 982 | 983 | SetBackColor(cLtBlue); 984 | local int i; 985 | local uint foreign_start = abc_header.foreign_off; 986 | local uint foreign_end = foreign_start + abc_header.foreign_size; 987 | local uint class_addr; 988 | for (i = 0; i < size; i++) { 989 | class_addr = class_def[i]; 990 | FSeek(class_addr); 991 | if (foreign_start <= class_addr && class_addr < foreign_end) 992 | ForeignClass abc_class_items ; 993 | else 994 | class_item abc_class_items ; 995 | } 996 | FSeek(pos); 997 | } ClassIndex; 998 | 999 | typedef struct (int size) { 1000 | uint offsets[size] ; 1001 | FAlign(4); 1002 | local uint64 pos = FTell(); 1003 | 1004 | SetBackColor(cLtRed); 1005 | local uint i; 1006 | local uint lnp_addr; 1007 | for (i = 0; i < size; i++) { 1008 | lnp_addr = offsets[i]; 1009 | FSeek(lnp_addr); 1010 | LineNumberProgram abc_line_num_programs ; 1011 | } 1012 | FSeek(pos); 1013 | } LineNumberProgramIndex; 1014 | 1015 | typedef struct (int size) { 1016 | uint offsets[size] ; 1017 | FAlign(4); 1018 | local uint64 pos = FTell(); 1019 | 1020 | SetBackColor(cLtAqua); 1021 | local uint i; 1022 | local uint literalarray_addr; 1023 | for (i = 0; i < size; i++) { 1024 | literalarray_addr = offsets[i]; 1025 | FSeek(literalarray_addr); 1026 | LiteralArray abc_literalarrays ; 1027 | } 1028 | FSeek(pos); 1029 | } LiteralArrayIndex; 1030 | 1031 | typedef struct (int size) { 1032 | SetBackColor(0xa030a0); 1033 | RegionHeader region_headers[size] ; 1034 | FAlign(4); 1035 | } RegionIndex; 1036 | 1037 | SetBackColor(cLtGreen); 1038 | Header abc_header ; 1039 | 1040 | FSeek(abc_header.index_section_off); 1041 | SetBackColor(0xa030a0); 1042 | RegionIndex abc_region_idxs(abc_header.num_index_regions) ; 1043 | 1044 | local uint64 modulerecord_literalarrs[abc_region_idxs.region_headers.class_idx_size]; // Keep track of module record offsets when we parse Field. 1045 | 1046 | FSeek(abc_header.class_idx_off); 1047 | SetBackColor(cDkBlue); 1048 | ClassIndex abc_class_idxs(abc_header.num_classes) ; 1049 | 1050 | FSeek(abc_header.lnp_idx_off); 1051 | SetBackColor(cDkRed); 1052 | LineNumberProgramIndex abc_line_num_program_idxs(abc_header.num_lnps) ; 1053 | 1054 | FSeek(abc_header.literalarray_idx_off); 1055 | SetBackColor(cDkAqua); 1056 | LiteralArrayIndex abc_literalarray_idxs(abc_header.num_literalarrays) ; 1057 | --------------------------------------------------------------------------------