// parseSubs parses the graph representations of the given high-level control // flow primitives. If unable to locate a subgraph, a second attempt is made by // prepending $GOPATH/src/decomp.org/decomp/cmd/restructure/primitives/ to the // subgraph path. func parseSubs(subPaths []string) (subs []*graphs.SubGraph, err error) { // Prepend $GOPATH/src/decomp.org/decomp/cmd/restructure/primitives/ to the path // of missing subgraphs. subDir, err := goutil.SrcDir("decomp.org/decomp/cmd/restructure/primitives") if err != nil { return nil, errutil.Err(err) } for i, subPath := range subPaths { if ok, _ := osutil.Exists(subPath); !ok { subPath = filepath.Join(subDir, subPath) subPaths[i] = subPath } } // Parse subgraphs representing control flow primitives. for _, subPath := range subPaths { sub, err := graphs.ParseSubGraph(subPath) if err != nil { return nil, errutil.Err(err) } subs = append(subs, sub) } return subs, nil }
// locate parses the provided graphs and tries to locate isomorphisms of the // subgraph in the graph. func locate(graphPath, subPath string) error { // Parse graph. graph, err := dot.ParseFile(graphPath) if err != nil { return errutil.Err(err) } // Search for subgraph in GOPATH if not found. if ok, _ := osutil.Exists(subPath); !ok { dir, err := goutil.SrcDir("decomp.org/decomp/graphs/testdata/primitives") if err != nil { return errutil.Err(err) } subPath = filepath.Join(dir, subPath) } sub, err := graphs.ParseSubGraph(subPath) if err != nil { return errutil.Err(err) } // Locate isomorphisms. found := false if len(flagStart) > 0 { // Locate an isomorphism of sub in graph which starts at the node // specified by the "-start" flag. m, ok := iso.Isomorphism(graph, flagStart, sub) if ok { found = true printMapping(graph, sub, m) } } else { // Locate all isomorphisms of sub in graph. var names []string for name := range graph.Nodes.Lookup { names = append(names, name) } sort.Strings(names) for _, name := range names { m, ok := iso.Isomorphism(graph, name, sub) if !ok { continue } found = true printMapping(graph, sub, m) } } if !found { fmt.Println("not found.") } return nil }
// storeFile stores the given Go source code to the provided file path. func storeFile(goPath string, file *ast.File) error { // Don't force overwrite Go output file. if !flagForce { if ok, _ := osutil.Exists(goPath); ok { return errutil.Newf("output file %q already exists", goPath) } } f, err := os.Create(goPath) if err != nil { return err } defer f.Close() fset := token.NewFileSet() return printer.Fprint(f, fset, file) }
// flac2wav converts the provided FLAC file to a WAV file. func flac2wav(path string) error { // Open FLAC file. stream, err := flac.Open(path) if err != nil { return err } defer stream.Close() // Create WAV file. wavPath := pathutil.TrimExt(path) + ".wav" if !flagForce { exists, err := osutil.Exists(wavPath) if err != nil { return err } if exists { return fmt.Errorf("the file %q exists already", wavPath) } } fw, err := os.Create(wavPath) if err != nil { return err } defer fw.Close() // Create WAV encoder. conf := audio.Config{ Channels: int(stream.Info.NChannels), SampleRate: int(stream.Info.SampleRate), } enc, err := wav.NewEncoder(fw, conf) if err != nil { return err } defer enc.Close() for { // Decode FLAC audio samples. frame, err := stream.ParseNext() if err != nil { if err == io.EOF { break } return err } // Encode WAV audio samples. samples := make(audio.Int16, 1) for i := 0; i < int(frame.BlockSize); i++ { for _, subframe := range frame.Subframes { samples[0] = int16(subframe.Samples[i]) _, err = enc.Write(samples) if err != nil { return err } } } } return nil }
// ll2go parses the provided LLVM IR assembly file and decompiles it to Go // source code. func ll2go(llPath string) error { // File name and file path without extension. baseName := pathutil.FileName(llPath) basePath := pathutil.TrimExt(llPath) // TODO: Create graphs in /tmp/xxx_graphs/*.dot // Create temporary foo.dot file, e.g. // // foo.ll -> foo_graphs/*.dot dotDir := basePath + "_graphs" if ok, _ := osutil.Exists(dotDir); !ok { if !flagQuiet { log.Printf("Creating control flow graphs for %q.\n", filepath.Base(llPath)) } cmd := exec.Command("ll2dot", "-q", "-funcs", flagFuncs, "-f", llPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { return errutil.Err(err) } } // Create temporary foo.bc file, e.g. // // foo.ll -> foo.bc bcPath := fmt.Sprintf("/tmp/%s.bc", baseName) cmd := exec.Command("llvm-as", "-o", bcPath, llPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { return errutil.Err(err) } // Remove temporary foo.bc file. defer func() { err = os.Remove(bcPath) if err != nil { log.Fatalln(errutil.Err(err)) } }() // Parse foo.bc module, err := llvm.ParseBitcodeFile(bcPath) if err != nil { return errutil.Err(err) } defer module.Dispose() // Get function names. var funcNames []string if len(flagFuncs) > 0 { // Get function names from command line flag: // // -funcs="foo,bar" funcNames = strings.Split(flagFuncs, ",") } else { // Get all function names. for llFunc := module.FirstFunction(); !llFunc.IsNil(); llFunc = llvm.NextFunction(llFunc) { if llFunc.IsDeclaration() { // Ignore function declarations (e.g. functions without bodies). continue } funcNames = append(funcNames, llFunc.Name()) } } // Locate package name. pkgName := flagPkgName if len(flagPkgName) == 0 { pkgName = baseName for _, funcName := range funcNames { if funcName == "main" { pkgName = "main" break } } } // Create foo.go. file := &ast.File{ Name: newIdent(pkgName), } // TODO: Implement support for global variables. // Parse each function. for _, funcName := range funcNames { if !flagQuiet { log.Printf("Parsing function: %q\n", funcName) } graph, err := parseCFG(basePath, funcName) if err != nil { return errutil.Err(err) } // Structure the CFG. dotDir := basePath + "_graphs" dotName := funcName + ".dot" dotPath := path.Join(dotDir, dotName) jsonName := funcName + ".json" jsonPath := path.Join(dotDir, jsonName) if ok, _ := osutil.Exists(jsonPath); !ok { cmd := exec.Command("restructure", "-o", jsonPath, dotPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if !flagQuiet { log.Printf("Structuring function: %q\n", funcName) } err = cmd.Run() if err != nil { return errutil.Err(err) } } var hprims []*xprimitive.Primitive fr, err := os.Open(jsonPath) if err != nil { return errutil.Err(err) } defer fr.Close() dec := json.NewDecoder(fr) err = dec.Decode(&hprims) if err != nil { return errutil.Err(err) } f, err := parseFunc(graph, module, funcName, hprims) if err != nil { return errutil.Err(err) } file.Decls = append(file.Decls, f) if flagVerbose && !flagQuiet { printFunc(f) } } // Store Go source code to file. goPath := basePath + ".go" if !flagQuiet { log.Printf("Creating: %q\n", goPath) } return storeFile(goPath, file) }
func initialize() (err error) { Updates = make(map[string]bool) // Will set nyfiken root differently depending on operating system. setNyfikenRoot() ConfigPath = NyfikenRoot + "/config.ini" PagesPath = NyfikenRoot + "/pages.ini" UpdatesPath = NyfikenRoot + "/updates.gob" CacheRoot = NyfikenRoot + "/cache/" ReadRoot = NyfikenRoot + "/read/" DebugRoot = NyfikenRoot + "/debug/" DebugCacheRoot = NyfikenRoot + "/debug/cache/" DebugReadRoot = NyfikenRoot + "/debug/read/" // Load uncleared updates from last execution. err = LoadUpdates() if err != nil { return errutil.Err(err) } // Create a nyfiken config folder if it doesn't exist. found, err := osutil.Exists(NyfikenRoot) if err != nil { return errutil.Err(err) } if !found { err := os.Mkdir(NyfikenRoot, DefaultFolderPerms) if err != nil { return errutil.Err(err) } } found, err = osutil.Exists(CacheRoot) if err != nil { return errutil.Err(err) } if !found { err := os.Mkdir(CacheRoot, DefaultFolderPerms) if err != nil { return errutil.Err(err) } } found, err = osutil.Exists(ReadRoot) if err != nil { return errutil.Err(err) } if !found { err := os.Mkdir(ReadRoot, DefaultFolderPerms) if err != nil { return errutil.Err(err) } } found, err = osutil.Exists(DebugRoot) if err != nil { return errutil.Err(err) } if !found { err := os.Mkdir(DebugRoot, DefaultFolderPerms) if err != nil { return errutil.Err(err) } } found, err = osutil.Exists(DebugCacheRoot) if err != nil { return errutil.Err(err) } if !found { err := os.Mkdir(DebugCacheRoot, DefaultFolderPerms) if err != nil { return errutil.Err(err) } } found, err = osutil.Exists(DebugReadRoot) if err != nil { return errutil.Err(err) } if !found { err := os.Mkdir(DebugReadRoot, DefaultFolderPerms) if err != nil { return errutil.Err(err) } } return nil }
// flac2wav converts the provided FLAC file to a WAV file. func flac2wav(path string) error { // Open FLAC file. fr, err := os.Open(path) if err != nil { return err } defer fr.Close() // Create FLAC decoder. dec, magic, err := audio.NewDecoder(fr) if err != nil { return err } fmt.Println("magic:", magic) conf := dec.Config() fmt.Println("conf:", conf) // Create WAV file. wavPath := pathutil.TrimExt(path) + ".wav" if !flagForce { exists, err := osutil.Exists(wavPath) if err != nil { return err } if exists { return fmt.Errorf("the file %q exists already", wavPath) } } fw, err := os.Create(wavPath) if err != nil { return err } defer fw.Close() // Create WAV encoder. enc, err := wav.NewEncoder(fw, conf) if err != nil { return err } defer enc.Close() // Encode WAV audio samples copied from the FLAC decoder. // TODO(u): Replace with audio.Copy as soon as that doesn't cause audio // sample conversions. buf := make(audio.PCM16Samples, (32*1024)/8) for { nr, er := dec.Read(buf) if nr > 0 { nw, ew := enc.Write(buf[0:nr]) if ew != nil { return ew } if nr != nw { return audio.ErrShortWrite } } if er == audio.EOS { return nil } if er != nil { return er } } }
// locateAndMerge parses the provided graphs and tries to merge isomorphisms of // the subgraph in the graph into single nodes. func locateAndMerge(graphPath, subPath string) error { // Parse graph. graph, err := dot.ParseFile(graphPath) if err != nil { return errutil.Err(err) } // Search for subgraph in GOPATH if not found. if ok, _ := osutil.Exists(subPath); !ok { dir, err := goutil.SrcDir("decomp.org/decomp/graphs/testdata/primitives") if err != nil { return errutil.Err(err) } subPath = filepath.Join(dir, subPath) } sub, err := graphs.ParseSubGraph(subPath) if err != nil { return errutil.Err(err) } // Merge isomorphisms. found := false if len(flagStart) > 0 { // Merge an isomorphism of sub in graph which starts at the node // specified by the "-start" flag. m, ok := iso.Isomorphism(graph, flagStart, sub) if ok { found = true printMapping(graph, sub, m) _, err := merge.Merge(graph, m, sub) if err != nil { return errutil.Err(err) } } } else { // Merge all isomorphisms of sub in graph. for { m, ok := iso.Search(graph, sub) if !ok { break } found = true printMapping(graph, sub, m) _, err := merge.Merge(graph, m, sub) if err != nil { return errutil.Err(err) } } } // Store DOT and PNG representation of graph. if found { err = dump(graph) if err != nil { return errutil.Err(err) } } else { fmt.Println("not found.") } return nil }