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  }