github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/undump/undump.go (about) 1 package undump 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "io" 7 8 "github.com/hirochachacha/plua/internal/limits" 9 "github.com/hirochachacha/plua/internal/version" 10 "github.com/hirochachacha/plua/object" 11 "github.com/hirochachacha/plua/opcode" 12 ) 13 14 var ( 15 errIntegerOverflow = &Error{errors.New("integer overflow")} 16 errShortHeader = &Error{errors.New("header is too short")} 17 errSignatureMismatch = &Error{errors.New("signature mismatch")} 18 errVersionMismatch = &Error{errors.New("version mismatch")} 19 errFormatMismatch = &Error{errors.New("format mismatch")} 20 errDataMismatch = &Error{errors.New("data mismatch")} 21 errInvalidIntSize = &Error{errors.New("int size is invalid")} 22 errInvalidIntegerSize = &Error{errors.New("integer size is invalid")} 23 errInvalidNumberSize = &Error{errors.New("number size is invalid")} 24 errInvalidInstructionSize = &Error{errors.New("instruction size is invalid")} 25 errEndiannessMismatch = &Error{errors.New("endianness mismatch")} 26 errNumberFormatMismatch = &Error{errors.New("number format mismatch")} 27 errMalformedByteCode = &Error{errors.New("malformed byte code detected")} 28 errTruncatedChunk = &Error{errors.New("truncated precompiled chunk")} 29 ) 30 31 const bufferSize = 20 32 33 type Mode uint // currently, no mode are defined 34 35 func Undump(r io.Reader, mode Mode) (*object.Proto, error) { 36 u := &undumper{ 37 r: r, 38 order: binary.LittleEndian, 39 } 40 41 if br, ok := r.(io.ByteReader); ok { 42 u.byte = func() (int, error) { 43 c, err := br.ReadByte() 44 return int(c), err 45 } 46 } else { 47 u.byte = func() (int, error) { 48 _, err := io.ReadFull(r, u.bs[:1]) 49 return int(u.bs[0]), err 50 } 51 } 52 53 err := u.loadHeader() 54 if err != nil { 55 if err == io.EOF || err == io.ErrUnexpectedEOF { 56 return nil, errShortHeader 57 } 58 59 return nil, err 60 } 61 62 n, err := u.loadByte() 63 if err != nil { 64 if err == io.EOF || err == io.ErrUnexpectedEOF { 65 return nil, errTruncatedChunk 66 } 67 68 return nil, err 69 } 70 71 p, err := u.loadFunction("") 72 if err != nil { 73 if err == io.EOF || err == io.ErrUnexpectedEOF { 74 return nil, errTruncatedChunk 75 } 76 77 return nil, err 78 } 79 80 if n != len(p.Upvalues) { 81 return nil, errMalformedByteCode 82 } 83 84 return p, nil 85 } 86 87 type undumper struct { 88 r io.Reader 89 order binary.ByteOrder 90 91 bs [bufferSize]byte // buffer for short string 92 93 byte func() (int, error) 94 int func(*undumper) (int, error) 95 sizeT func(*undumper) (int, error) 96 integer func(*undumper) (object.Integer, error) 97 number func(*undumper) (object.Number, error) 98 } 99 100 func (u *undumper) loadByte() (int, error) { 101 return u.byte() 102 } 103 104 func (u *undumper) loadBool() (bool, error) { 105 c, err := u.loadByte() 106 107 return c != 0, err 108 } 109 110 func (u *undumper) loadInt() (int, error) { 111 return u.int(u) 112 } 113 114 func (u *undumper) loadSizeT() (int, error) { 115 return u.sizeT(u) 116 } 117 118 func (u *undumper) loadInst() (opcode.Instruction, error) { 119 var i uint32 120 err := binary.Read(u.r, u.order, &i) 121 return opcode.Instruction(i), err 122 } 123 124 func (u *undumper) loadBoolean() (object.Boolean, error) { 125 c, err := u.loadByte() 126 127 return object.Boolean(c != 0), err 128 } 129 130 func (u *undumper) loadInteger() (object.Integer, error) { 131 return u.integer(u) 132 } 133 134 func (u *undumper) loadNumber() (object.Number, error) { 135 return u.number(u) 136 } 137 138 func (u *undumper) loadString() (string, error) { 139 length, err := u.loadByte() 140 if err != nil { 141 return "", err 142 } 143 144 if length == 0xFF { 145 length, err = u.loadSizeT() 146 } 147 148 if length == 0 { 149 return "", nil 150 } 151 152 length-- 153 154 var bs []byte 155 156 if length <= len(u.bs) { 157 bs = u.bs[:length] 158 } else { 159 bs = make([]byte, length) 160 } 161 162 _, err = io.ReadFull(u.r, bs) 163 164 return string(bs), err 165 } 166 167 func (u *undumper) loadCode() ([]opcode.Instruction, error) { 168 n, err := u.loadInt() 169 if err != nil { 170 return nil, err 171 } 172 173 code := make([]opcode.Instruction, n) 174 175 err = binary.Read(u.r, u.order, code) 176 177 return code, err 178 } 179 180 func (u *undumper) loadConstants() ([]object.Value, error) { 181 n, err := u.loadInt() 182 if err != nil { 183 return nil, err 184 } 185 186 constants := make([]object.Value, n) 187 188 var v object.Value 189 var t int 190 for i := 0; i < n; i++ { 191 t, err = u.loadByte() 192 if err != nil { 193 return nil, err 194 } 195 196 switch object.Type(t) { 197 case object.TNIL: 198 v = nil 199 case object.TBOOLEAN: 200 v, err = u.loadBoolean() 201 case object.TNUMFLT: 202 v, err = u.loadNumber() 203 case object.TNUMINT: 204 v, err = u.loadInteger() 205 case object.TSHRSTR, object.TLNGSTR: 206 s, _err := u.loadString() 207 v = object.String(s) 208 err = _err 209 default: 210 panic("unexpected") 211 } 212 213 if err != nil { 214 return nil, err 215 } 216 217 constants[i] = v 218 } 219 220 return constants, nil 221 } 222 223 func (u *undumper) loadUpvalues() ([]object.UpvalueDesc, error) { 224 n, err := u.loadInt() 225 if err != nil { 226 return nil, err 227 } 228 229 upvalues := make([]object.UpvalueDesc, n) 230 231 var instack bool 232 var idx int 233 for i := 0; i < n; i++ { 234 instack, err = u.loadBool() 235 if err != nil { 236 return nil, err 237 } 238 239 idx, err = u.loadByte() 240 if err != nil { 241 return nil, err 242 } 243 244 upvalues[i].Instack = instack 245 upvalues[i].Index = idx 246 } 247 248 return upvalues, nil 249 } 250 251 func (u *undumper) loadProtos(source string) ([]*object.Proto, error) { 252 n, err := u.loadInt() 253 if err != nil { 254 return nil, err 255 } 256 257 protos := make([]*object.Proto, n) 258 259 for i := 0; i < n; i++ { 260 protos[i], err = u.loadFunction(source) 261 262 if err != nil { 263 return nil, err 264 } 265 } 266 267 return protos, nil 268 } 269 270 func (u *undumper) loadDebug() (lineInfo []int, locVars []object.LocVar, upvalueNames []string, err error) { 271 var n int 272 273 n, err = u.loadInt() 274 if err != nil { 275 return 276 } 277 278 lineInfo = make([]int, n) 279 280 for i := 0; i < n; i++ { 281 lineInfo[i], err = u.loadInt() 282 283 if err != nil { 284 return 285 } 286 } 287 288 n, err = u.loadInt() 289 if err != nil { 290 return 291 } 292 293 locVars = make([]object.LocVar, n) 294 295 var name string 296 var startPC int 297 var endPC int 298 for i := 0; i < n; i++ { 299 name, err = u.loadString() 300 if err != nil { 301 return 302 } 303 304 startPC, err = u.loadInt() 305 if err != nil { 306 return 307 } 308 309 endPC, err = u.loadInt() 310 if err != nil { 311 return 312 } 313 314 locVars[i].Name = name 315 locVars[i].StartPC = startPC 316 locVars[i].EndPC = endPC 317 } 318 319 n, err = u.loadInt() 320 if err != nil { 321 return 322 } 323 324 upvalueNames = make([]string, n) 325 for i := 0; i < n; i++ { 326 upvalueNames[i], err = u.loadString() 327 328 if err != nil { 329 return 330 } 331 } 332 333 return 334 } 335 336 func (u *undumper) loadFunction(psource string) (*object.Proto, error) { 337 source, err := u.loadString() 338 if len(source) == 0 { 339 source = psource 340 } 341 lineDefined, err := u.loadInt() 342 if err != nil { 343 return nil, err 344 } 345 lastLineDefined, err := u.loadInt() 346 if err != nil { 347 return nil, err 348 } 349 nParams, err := u.loadByte() 350 if err != nil { 351 return nil, err 352 } 353 isVararg, err := u.loadBool() 354 if err != nil { 355 return nil, err 356 } 357 maxStackSize, err := u.loadByte() 358 if err != nil { 359 return nil, err 360 } 361 code, err := u.loadCode() 362 if err != nil { 363 return nil, err 364 } 365 constants, err := u.loadConstants() 366 if err != nil { 367 return nil, err 368 } 369 upvalues, err := u.loadUpvalues() 370 if err != nil { 371 return nil, err 372 } 373 protos, err := u.loadProtos(source) 374 if err != nil { 375 return nil, err 376 } 377 lineInfo, locVars, upvalueNames, err := u.loadDebug() 378 if err != nil { 379 return nil, err 380 } 381 for i, name := range upvalueNames { 382 upvalues[i].Name = name 383 } 384 385 p := &object.Proto{ 386 Code: code, 387 Constants: constants, 388 Protos: protos, 389 Upvalues: upvalues, 390 Source: source, 391 LineDefined: lineDefined, 392 LastLineDefined: lastLineDefined, 393 NParams: nParams, 394 IsVararg: isVararg, 395 MaxStackSize: maxStackSize, 396 LineInfo: lineInfo, 397 LocVars: locVars, 398 } 399 400 return p, nil 401 } 402 403 func (u *undumper) loadHeader() error { 404 header := make([]byte, 12) 405 406 _, err := io.ReadFull(u.r, header) 407 408 if err != nil { 409 if err == io.ErrShortBuffer { 410 return errShortHeader 411 } 412 return err 413 } 414 415 if string(header[:4]) != version.LUA_SIGNATURE { 416 return errSignatureMismatch 417 } 418 419 if header[4] != version.LUAC_VERSION { 420 return errVersionMismatch 421 } 422 423 if header[5] != version.LUAC_FORMAT { 424 return errFormatMismatch 425 } 426 427 if string(header[6:]) != version.LUAC_DATA { 428 return errDataMismatch 429 } 430 431 intSize, err := u.loadByte() 432 if err != nil { 433 return err 434 } 435 sizeTSize, err := u.loadByte() 436 if err != nil { 437 return err 438 } 439 instSize, err := u.loadByte() 440 if err != nil { 441 return err 442 } 443 if instSize != opcode.InstructionSize { 444 return errInvalidInstructionSize 445 } 446 integerSize, err := u.loadByte() 447 if err != nil { 448 return err 449 } 450 numberSize, err := u.loadByte() 451 if err != nil { 452 return err 453 } 454 455 u.int, err = makeInt(intSize) 456 if err != nil { 457 return err 458 } 459 u.sizeT, err = makeInt(sizeTSize) 460 if err != nil { 461 return err 462 } 463 u.integer, err = makeInteger(integerSize) 464 if err != nil { 465 return err 466 } 467 u.number, err = makeNumber(numberSize) 468 if err != nil { 469 return err 470 } 471 472 i, err := u.loadInteger() 473 if err != nil { 474 return err 475 } 476 477 if i != version.LUAC_INT { 478 479 // guess endian 480 switch u.order { 481 case binary.LittleEndian: 482 if isReverseEndian(int64(i), integerSize) { 483 u.order = binary.BigEndian 484 } else { 485 return errNumberFormatMismatch 486 } 487 case binary.BigEndian: 488 if isReverseEndian(int64(i), integerSize) { 489 u.order = binary.LittleEndian 490 } else { 491 return errNumberFormatMismatch 492 } 493 default: 494 return errEndiannessMismatch 495 } 496 } 497 498 f, err := u.loadNumber() 499 if err != nil { 500 return err 501 } 502 503 if f != version.LUAC_NUM { 504 return errNumberFormatMismatch 505 } 506 507 return nil 508 } 509 510 func makeInt(size int) (f func(*undumper) (int, error), err error) { 511 switch size { 512 case 1: 513 f = func(u *undumper) (int, error) { 514 var i int8 515 err := binary.Read(u.r, u.order, &i) 516 return int(i), err 517 } 518 case 2: 519 f = func(u *undumper) (int, error) { 520 var i int16 521 err := binary.Read(u.r, u.order, &i) 522 return int(i), err 523 } 524 case 4: 525 f = func(u *undumper) (int, error) { 526 var i int32 527 err := binary.Read(u.r, u.order, &i) 528 return int(i), err 529 } 530 case 8: 531 f = func(u *undumper) (int, error) { 532 var i int64 533 err := binary.Read(u.r, u.order, &i) 534 if err != nil { 535 return 0, err 536 } 537 538 if limits.IntSize == 4 && (i > limits.MaxInt || i < limits.MinInt) { 539 return 0, errIntegerOverflow 540 } 541 542 return int(i), nil 543 } 544 default: 545 err = errInvalidIntSize 546 } 547 548 return 549 } 550 551 func makeInteger(size int) (f func(*undumper) (object.Integer, error), err error) { 552 switch size { 553 case 1: 554 f = func(u *undumper) (object.Integer, error) { 555 var i int8 556 err := binary.Read(u.r, u.order, &i) 557 return object.Integer(i), err 558 } 559 case 2: 560 f = func(u *undumper) (object.Integer, error) { 561 var i int16 562 err := binary.Read(u.r, u.order, &i) 563 return object.Integer(i), err 564 } 565 case 4: 566 f = func(u *undumper) (object.Integer, error) { 567 var i int32 568 err := binary.Read(u.r, u.order, &i) 569 return object.Integer(i), err 570 } 571 case 8: 572 f = func(u *undumper) (object.Integer, error) { 573 var i int64 574 err := binary.Read(u.r, u.order, &i) 575 if err != nil { 576 return 0, err 577 } 578 579 return object.Integer(i), nil 580 } 581 default: 582 err = errInvalidIntegerSize 583 } 584 585 return 586 } 587 588 func makeNumber(size int) (f func(*undumper) (object.Number, error), err error) { 589 switch size { 590 case 4: 591 f = func(u *undumper) (object.Number, error) { 592 var f float32 593 err := binary.Read(u.r, u.order, &f) 594 return object.Number(f), err 595 } 596 case 8: 597 f = func(u *undumper) (object.Number, error) { 598 var f float64 599 err := binary.Read(u.r, u.order, &f) 600 return object.Number(f), err 601 } 602 default: 603 err = errInvalidNumberSize 604 } 605 606 return 607 } 608 609 func isReverseEndian(i int64, size int) bool { 610 var r int64 611 612 switch size { 613 case 1: 614 r = int64(int8(i)) 615 case 2: 616 r = i & 0xFF 617 r = (r << 8) | ((i >> 8) & 0xFF) 618 case 4: 619 r = i & 0xFF 620 621 r = (r << 8) | ((i >> 8) & 0xFF) 622 r = (r << 8) | ((i >> 16) & 0xFF) 623 r = (r << 8) | ((i >> 24) & 0xFF) 624 case 8: 625 r = i & 0xFF 626 627 r = (r << 8) | ((i >> 8) & 0xFF) 628 r = (r << 8) | ((i >> 16) & 0xFF) 629 r = (r << 8) | ((i >> 24) & 0xFF) 630 r = (r << 8) | ((i >> 32) & 0xFF) 631 r = (r << 8) | ((i >> 40) & 0xFF) 632 r = (r << 8) | ((i >> 48) & 0xFF) 633 r = (r << 8) | ((i >> 56) & 0xFF) 634 default: 635 panic("unreachable") 636 } 637 638 return i == r 639 }