Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Manipulating racket bytecode

License

NotificationsYou must be signed in to change notification settings

bennn/zordoz

Repository files navigation

Build StatusCoverage StatusScribble

ZORDOZ speaks to you! His chosen ones.

This is an explorer for Racket .zo files.

Tested to work on Racketv6.5For compatibility with older versions, see thev6.1andv6.2andv6.3branches of this repo.(Note that installing throughraco will choose the available version, if any, matching your Racket install.)

Typed Racket users can(require zordoz/typed) for type-annotated bindings fromzordoz.Also,zordoz/typed/zo-structs is a safe wrapper around Racket'scompiler/zo-structs library.

Install

You have two options.

  1. Install fromraco by runningraco pkg install zordoz
  2. Build from source by cloning this repo and usingraco:git clone https://github.com/bennn/zordoz; raco pkg install zordoz/

To run tests, doraco test zordoz.Tests are located in thetest submodule of each source file.

Usage

Zordoz provides araco zordoz command.

REPL

Activate the REPL by giving a path to a compiled file.

raco zordoz FILE.zo

Passing the-t option uses typed racket code.Beware, the typed racket version is up to 5x slower than untyped because of contracts with thecompiler/zo-lib structs.

The REPL accepts the following commands:

  • alst prints all command aliases; for example, the repl treats the words 'alst' and 'aliases' the same way
  • back goes back to the previous context
  • dive ARG changes context to a new zo struct or list (other dives are not permitted)
  • find ARG searches for matches toARG and, if successful, changes context to the list of results
  • help prints information about these commands
  • info prints data about the current context
  • jump reverts to a previously saved context
  • save marks the current context as a target forjump
  • quit exits the interpreter

The functions implementing thedive,find, andinfo commands are available outside the REPL.Check theguide for a summary.

Quick Search

Running:

./zordoz -f branch -f lam -f closure FILE.zo

Will count and print the number of times the zo structsbranchlam andclosure appear.This may take a while, depending on the size of the bytecode file.You can limit the search depth by passing a natural number with the-l flag.

See thedecompilation guide for a list of all zo struct names.

Background

Racket bytecode is stored in files with a.zoextension.This tool makes it easier to explore the bytecode representation of a file, whether or not you have access to the file's source code.

Given a.zo file, we decompile the bytecode into a struct (aka, a "zo-struct") using Racket's built-indecompilation API.The REPL loads this struct as its initialcontext and begins accepting commands, making it easy to visualize and explore Racket bytecode.

Example

Suppose we create and compile a small racket file:

> echo -e "#lang racket/base\n(if #t (+ 1 1) 0)" > test.rkt> raco make test.rkt

The actual bytecode is not human readable.Neither is the struct representation output byzo-parse:

> echo -e '#lang racket/base\n(require compiler/zo-parse)\n(call-with-input-file "compiled/test_rkt.zo"\n  (lambda (fd) (displayln (zo-parse fd))))' > print-test.rkt> racket print-test.rkt#s((compilation-top zo 0) 0 #s((prefix zo 0) 0 (#f) ()) #s((mod form 0 zo 0) test test #<module-path-index> #s((prefix zo 0) 0 (#s((module-variable zo 0) #<module-path-index> print-values 0 0 #s((function-shape zo 0) #(struct:arity-at-least 0) #f))) ()) ((0 () ()) (1 () ()) (#f () ())) ((0 #<module-path-index>) (1) (-1) (#f)) (#s((apply-values expr 0 form 0 zo 0) #s((toplevel expr 0 form 0 zo 0) 0 0 #t #t) 2)) () ((0 () ())) 0 #s((toplevel expr 0 form 0 zo 0) 0 0 #f #f) #f #t () (#s((mod form 0 zo 0) (test configure-runtime) configure-runtime #<module-path-index> #s((prefix zo 0) 0 (#s((module-variable zo 0) #<module-path-index> configure 0 0 #s((function-shape zo 0) 1 #f))) ()) ((0 () ()) (1 () ()) (#f () ())) ((0 #<module-path-index> #<module-path-index>) (1) (-1) (#f)) (#s((application expr 0 form 0 zo 0) #s((primval expr 0 form 0 zo 0) 1000) (#t))) () ((0 () ())) 1 #s((toplevel expr 0 form 0 zo 0) 0 0 #f #f) #f #t () () ())) ()))

ZORDOZ offers a more readable presentation.Below is a sample interactive session with the same small file (interspersed with commentary):

> racket zordoz.rkt compiled/test_rkt.zo INFO: Loading bytecode file 'compiled/test_rkt.zo'...INFO: Parsing bytecode...INFO: Parsing complete!--- Welcome to the .zo shell, version 0.1 'outlands' ---zo> info<struct:compilation-top>  max-let-depth : 0  prefix        : <struct:prefix>  code          : <struct:mod>

Thecompilation-top struct is at the top of most every.zo file.Things get more interesting as we explore the structs nested inside it.

zo> dive codezo> info<struct:mod>  name             : test  srcname          : test  self-modidx      : #<module-path-index>  prefix           : <struct:prefix>  provides         : 0 [] [] 1 [] [] #f [] []  requires         : 0 #<module-path-index> 1  -1  #f   body             : <struct:apply-values>  syntax-bodies    :  unexported       : 0  max-let-depth    : 0  dummy            : <struct:toplevel>  lang-info        : #f  internal-context : #t  flags            :  pre-submodules   : <struct:mod>[1]  post-submodules  : []

Themod struct represents a Racket module.This module has the nametest; inferred from our filenametest.rkt.

We could continuedive-ing into structs, or we can use the shell'sfind command to look for structs matching a name likemod orcompilation-top.Let's search forbranch structs.Maybe we can find theif-statement in our original code.

zo> find branchFIND returned 0 results

Nothing.Theif-statement has been optimized away.Let's try to find what it turned into by searching the body of the module.

zo> dive bodyzo> info(<struct:apply-values>)[1]

The syntax(<struct:NAME>)[LENGTH] denotes a list of zo-structs.LENGTH is the number of elements in the list--we candive into any valid index.

zo> dive 0zo> info<struct:apply-values>  proc      : <struct:expr>  args-expr : 2

Looks like ourif-statement was optimized into a constant,2.

Happy exploring!


[8]ページ先頭

©2009-2025 Movatter.jp