示例#1
0
文件: dis_tool.py 项目: vck/oil
def disassemble(co, indent, op_counts, f):
  """Copied from dis module.

  Args:
    co: code object
    indent: indentation to print with

  It doesn't do the indent we want.
  """
  def out(*args, **kwargs):
    print(*args, file=f, **kwargs)

  code = co.co_code
  labels = dis.findlabels(code)
  linestarts = dict(dis.findlinestarts(co))
  n = len(code)
  i = 0
  extended_arg = 0
  free = None

  while i < n:
      c = code[i]
      op = ord(c)

      op_counts[op] += 1

      if i in linestarts:
          if i > 0:
              out()
          prefix = linestarts[i]
      else:
          prefix = ''
      out('%s%4s' % (indent, prefix), end=' ')

      if i in labels:  # Jump targets get a special symbol
        arrow = '>>'
      else:
        arrow = '  '

      out(' %s %4r %-20s ' % (arrow, i, dis.opname[op]), end=' ')
      i += 1
      if op >= dis.HAVE_ARGUMENT:
          oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
          extended_arg = 0
          i += 2
          if op == dis.EXTENDED_ARG:
              extended_arg = oparg*65536L

          oparg_str = None

          if op in dis.hasconst:
            c = co.co_consts[oparg]
            if isinstance(c, types.CodeType):
              # %r prints a memory address, which inhibits diffing
              oparg_str = '(code object %s %s %s)' % (
                  c.co_name, c.co_filename, c.co_firstlineno)
            else:
              oparg_str = '(%r)' % (c,)

          elif op in dis.hasname:
            oparg_str = '(%s)' % (co.co_names[oparg],)

          elif op in dis.hasjrel:
            oparg_str = '(to %r)' % (i + oparg,)

          elif op in dis.haslocal:
            oparg_str = '(%s)' % (co.co_varnames[oparg],)

          elif op in dis.hascompare:
            oparg_str = '(%s)' % (dis.cmp_op[oparg],)

          elif op in dis.hasfree:
            if free is None:
              free = co.co_cellvars + co.co_freevars
            oparg_str = '(%s)' % (free[oparg],)

          if oparg_str:
            out('%5r %s' % (oparg, oparg_str), end=' ')
          else:
            out('%5r' % oparg, end=' ')

      out()
示例#2
0
    def run_frame(self, frame):
        """Run a frame until it returns or raises an exception.

        This function raises GuestException or returns the return value.

        Corresponds to PyEval_EvalFrameEx in ceval.c.  That returns 'PyObject*
        retval' -- but how does it indicate an exception?

        I think retval is NULL, and then

        """
        # bytecode offset -> line number
        #print('frame %s ' % frame)
        # NOTE: Also done in Frmae.line_number()
        linestarts = dict(dis.findlinestarts(frame.f_code))
        #print('STARTS %s ' % linestarts)

        self._push_frame(frame)
        num_ticks = 0
        while True:
            num_ticks += 1

            opoffset = self.frame.f_lasti  # For logging only
            byteName, arguments = self.frame.decode_next()
            if self.verbose:
                self.logTick(byteName, arguments, opoffset, linestarts)

            # When unwinding the block stack, we need to keep track of why we
            # are doing it.

            # NOTE: In addition to returning why == 'exception', this can also
            # RAISE GuestException from recursive call via call_function.

            why = self.dispatch(byteName, arguments)
            if why == 'exception':
                # TODO: ceval calls PyTraceBack_Here, not sure what that does.
                pass

            if why == 'reraise':
                why = 'exception'

            if why != 'yield':

                # NOTE: why is used in a frame INTERNALLY after bytecode dispatch.
                # But what about ACROSS frames.  We need to unwind the call
                # stack too!  How is that done?
                # I don't want it to be done with GuestException!

                while why and frame.block_stack:
                    debug('WHY %s', why)
                    debug('STACK %s', frame.block_stack)
                    why = self.frame.handle_block_stack(why, self)

            if why:
                break

        # TODO: handle generator exception state

        self._pop_frame()

        if why == 'exception':
            exctype, value, tb = self.last_exception

            #debug('exctype: %s' % exctype)
            #debug('value: %s' % value)
            #debug('unused tb: %s' % tb)

            if self.more_info:
                # Recursive function calls can cause this I guess.
                if isinstance(value, GuestException):
                    raise value
                else:
                    # Raise an exception with the EMULATED (guest) stack frames.
                    raise GuestException(exctype, value, self.except_frames)
            else:
                raise exctype, value, tb

        #debug1('num_ticks: %d' % num_ticks)
        return self.return_value