From bfc7beb38234667f2f69a9e415a053161232ce98 Mon Sep 17 00:00:00 2001 From: Zorchenhimer Date: Sun, 14 Sep 2025 18:06:46 -0400 Subject: [PATCH] [script] Improve CDL logic - CDL data can now be output to a file. If --cdl-output isn't given, but --cdl is given, the input file is overwritten with the new data. If no CDL file is given no data is written. - Count arguments as "Code" - The SmartParse function no longer creates a new CDL. It will use and update what it was given. - The just-stats command does not write CDL data even though it generates it. Variable length arguments are not properly handled yet. Currently, just the OP code and first argument (length) are set at Code. The rest are ignored. --- cmd/script-decode.go | 21 ++++++++-- script/cdl.go | 94 ++++++++++++++++++++++++++++++++++++++++++++ script/parser.go | 27 +++++++++---- script/script.go | 1 + 4 files changed, 131 insertions(+), 12 deletions(-) diff --git a/cmd/script-decode.go b/cmd/script-decode.go index 5856eea..5a4929e 100644 --- a/cmd/script-decode.go +++ b/cmd/script-decode.go @@ -21,6 +21,7 @@ type Arguments struct { StatsFile string `arg:"--stats" help:"file to write some statistics to"` LabelFile string `arg:"--labels" help:"file containing address/label pairs"` CDL string `arg:"--cdl" help:"CodeDataLog json file"` + CDLOutput string `arg:"--cdl-output"` Smart bool `arg:"--smart"` start int @@ -103,10 +104,6 @@ func run(args *Arguments) error { return 0 }) - //for _, lbl := range scr.Labels { - // fmt.Println(lbl) - //} - for _, token := range scr.Tokens { fmt.Fprintln(outfile, token.String(scr.Labels)) } @@ -124,6 +121,22 @@ func run(args *Arguments) error { } } + if scr.CDL != nil { + cdlout := args.CDL + if args.CDLOutput != "" { + cdlout = args.CDLOutput + } + + if cdlout == "" { + return nil + } + + err = scr.CDL.WriteToFile(cdlout) + if err != nil { + return fmt.Errorf("Error writing CDL file: %w", err) + } + } + return nil } diff --git a/script/cdl.go b/script/cdl.go index c773ed1..4d6e7d5 100644 --- a/script/cdl.go +++ b/script/cdl.go @@ -6,6 +6,7 @@ import ( "encoding/json" "strconv" "fmt" + "slices" ) type CodeDataLog struct { @@ -28,8 +29,101 @@ var ( cdlUnknown cdlBit = 0x00 cdlCode cdlBit = 0x01 cdlData cdlBit = 0x02 + //cdlOpCode cdlBit = 0x04 ) +func (cdl *CodeDataLog) WriteToFile(filename string) error { + file, err := os.Create(filename) + if err != nil { + return err + } + + _, werr := cdl.WriteTo(file) + err = file.Close() + if err != nil { + return err + } + + return werr +} + +func getRanges(list []int) []CdlRange { + //fmt.Printf("getRanges(%v)\n", list) + data := []CdlRange{} + + start := -1 + //end := -1 + prev := -1 + for _, addr := range list { + if start == -1 { + start = addr + } + + if prev != -1 && prev != addr-1 { + data = append(data, CdlRange{ + Start: fmt.Sprintf("0x%X", start), + End: fmt.Sprintf("0x%X", prev), + }) + + //fmt.Printf("start: 0x%X end: 0x%X\n", start, prev) + + start = addr + } + + prev = addr + } + + if start != -1 && prev != -1 { + data = append(data, CdlRange{ + Start: fmt.Sprintf("0x%X", start), + End: fmt.Sprintf("0x%X", prev), + }) + + //fmt.Println("start:", start, "end:", prev) + } + + return data +} + +func (cdl *CodeDataLog) WriteTo(w io.Writer) (int64, error) { + clean := &CodeDataLog{ + Code: []CdlRange{}, + Data: []CdlRange{}, + } + + keys := []int{} + for k, _ := range cdl.cache { + keys = append(keys, k) + } + + slices.Sort(keys) + + code := []int{} + data := []int{} + + for _, k := range keys { + b := cdl.cache[k] + if b & cdlCode == cdlCode { + code = append(code, k) + } + + if b & cdlData == cdlData { + data = append(data, k) + } + } + + clean.Code = getRanges(code) + clean.Data = getRanges(data) + + raw, err := json.MarshalIndent(clean, "", "\t") + if err != nil { + return 0, err + } + + n, err := w.Write(raw) + return int64(n), err +} + func (cdl *CodeDataLog) setData(scriptOffset int) { if cdl.cache == nil { err := cdl.doCache() diff --git a/script/parser.go b/script/parser.go index 8c13e8f..7ef55d2 100644 --- a/script/parser.go +++ b/script/parser.go @@ -45,8 +45,6 @@ func SmartParse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, erro } p := &Parser{ - // Don't use CDL that was passed in - cdl: &CodeDataLog{}, script: &Script{ Tokens: []*Token{}, @@ -54,12 +52,18 @@ func SmartParse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, erro StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]), StartAddress: startAddr, Labels: make(map[int]*Label), // map[location]name + + CDL: cdl, }, rawinput: rawinput, startAddr: startAddr, } + if p.script.CDL == nil { + p.script.CDL = &CodeDataLog{} + } + tokenMap := make(map[int]*Token) // starting point is the third byte in the script. @@ -95,7 +99,7 @@ INNER: //fmt.Printf("{$%04X} %s\n", token.Offset, token.String(map[int]*Label{})) - p.cdl.setCode(p.current) + p.script.CDL.setCode(p.current) if raw < 0x80 { continue } @@ -181,21 +185,21 @@ func Parse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) { } p := &Parser{ - cdl: cdl, script: &Script{ Tokens: []*Token{}, Warnings: []string{}, StackAddress: (int(rawinput[1])<<8) | int(rawinput[0]), StartAddress: startAddr, Labels: make(map[int]*Label), // map[location]name + CDL: cdl, }, rawinput: rawinput, startAddr: startAddr, } tokenMap := make(map[int]*Token) - if p.cdl == nil { - p.cdl = &CodeDataLog{} + if p.script.CDL == nil { + p.script.CDL = &CodeDataLog{} } //earliestVar := len(p.rawinput)-2 @@ -217,8 +221,8 @@ func Parse(rawinput []byte, startAddr int, cdl *CodeDataLog) (*Script, error) { p.script.Tokens = append(p.script.Tokens, token) tokenMap[token.Offset] = token - if raw < 0x80 || p.cdl.IsData(p.current+startAddr) { // || p.current >= earliestVar { - if p.cdl.IsData(p.current+startAddr) { + if raw < 0x80 || p.script.CDL.IsData(p.current+startAddr) { // || p.current >= earliestVar { + if p.script.CDL.IsData(p.current+startAddr) { token.IsData = true //fmt.Print(".") //fmt.Printf("%#v\n", token) @@ -321,6 +325,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error { switch op.OpCount { case -1: // null terminated for ; p.current < len(p.rawinput); p.current++ { + p.script.CDL.setCode(p.current) val := ByteVal(p.rawinput[p.current]) args = append(args, val) if p.rawinput[p.current] == 0x00 { @@ -332,6 +337,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error { // FIXME: wtf makes this different from -3?? p.current++ l := int(p.rawinput[p.current]) + p.script.CDL.setCode(p.current) args = append(args, ByteVal(l)) p.current++ for c := 0; c < l; c++ { @@ -349,6 +355,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error { p.current++ l := int(p.rawinput[p.current]) args = append(args, ByteVal(l)) + p.script.CDL.setCode(p.current) p.current++ for c := 0; c < l; c++ { args = append(args, WordVal([2]byte{p.rawinput[p.current], p.rawinput[p.current+1]})) @@ -358,7 +365,10 @@ func (p *Parser) parseToken(token *Token, raw byte) error { case 2: args = append(args, WordVal([2]byte{p.rawinput[p.current+1], p.rawinput[p.current+2]})) + p.script.CDL.setCode(p.current+1) + p.script.CDL.setCode(p.current+2) p.current+=2 + //fmt.Printf("var at $%04X\n", val.Int()) //if val.Int() > p.startAddr && val.Int() < p.startAddr+len(p.rawinput) && p.earliestVar > val.Int() { // fmt.Printf("new earliest: $%04X\n", val.Int()) @@ -367,6 +377,7 @@ func (p *Parser) parseToken(token *Token, raw byte) error { case 1: p.current++ + p.script.CDL.setCode(p.current) args = append(args, ByteVal(p.rawinput[p.current])) } diff --git a/script/script.go b/script/script.go index 07825f3..4fcf37d 100644 --- a/script/script.go +++ b/script/script.go @@ -11,6 +11,7 @@ type Script struct { StackAddress int Labels map[int]*Label + CDL *CodeDataLog } func (s *Script) Stats() Stats {