174 lines
4.4 KiB
Go
174 lines
4.4 KiB
Go
package mcp
|
|
|
|
import (
|
|
"loov.dev/lensm/internal/comments"
|
|
"loov.dev/lensm/internal/disasm"
|
|
)
|
|
|
|
type LineRangeDTO struct {
|
|
From int `json:"from"`
|
|
To int `json:"to"`
|
|
}
|
|
|
|
type FunctionCodeDTO struct {
|
|
Binary string `json:"binary,omitempty"`
|
|
Name string `json:"name"`
|
|
File string `json:"file,omitempty"`
|
|
Source []SourceFileDTO `json:"source"`
|
|
GoAsm []AsmLineDTO `json:"go_asm"`
|
|
NativeAsm []AsmLineDTO `json:"native_asm"`
|
|
Comments []comments.Record `json:"comments,omitempty"`
|
|
}
|
|
|
|
type SourceFileDTO struct {
|
|
File string `json:"file"`
|
|
Blocks []SourceBlockDTO `json:"blocks"`
|
|
}
|
|
|
|
type SourceBlockDTO struct {
|
|
From int `json:"from"`
|
|
To int `json:"to"`
|
|
Lines []SourceLineDTO `json:"lines"`
|
|
}
|
|
|
|
type SourceLineDTO struct {
|
|
File string `json:"file"`
|
|
Line int `json:"line"`
|
|
Text string `json:"text"`
|
|
Related []LineRangeDTO `json:"related,omitempty"`
|
|
Comment string `json:"comment,omitempty"`
|
|
}
|
|
|
|
type AsmLineDTO struct {
|
|
Index int `json:"index"`
|
|
PC uint64 `json:"pc"`
|
|
PCHex string `json:"pc_hex"`
|
|
Text string `json:"text"`
|
|
File string `json:"file,omitempty"`
|
|
Line int `json:"line,omitempty"`
|
|
Call string `json:"call,omitempty"`
|
|
RefPC uint64 `json:"ref_pc,omitempty"`
|
|
RefPCHex string `json:"ref_pc_hex,omitempty"`
|
|
RefOffset int `json:"ref_offset,omitempty"`
|
|
Comment string `json:"comment,omitempty"`
|
|
}
|
|
|
|
func BuildFunctionCodeDTO(binary string, code *disasm.Code, store *comments.Store) FunctionCodeDTO {
|
|
if code == nil {
|
|
return FunctionCodeDTO{Binary: comments.CleanPath(binary)}
|
|
}
|
|
|
|
dto := FunctionCodeDTO{
|
|
Binary: comments.CleanPath(binary),
|
|
Name: code.Name,
|
|
File: code.File,
|
|
Comments: store.Filter(code.Name, ""),
|
|
}
|
|
for _, src := range code.Source {
|
|
srcDTO := SourceFileDTO{File: src.File}
|
|
for _, block := range src.Blocks {
|
|
blockDTO := SourceBlockDTO{
|
|
From: block.From,
|
|
To: block.To,
|
|
}
|
|
for off, text := range block.Lines {
|
|
line := block.From + off
|
|
lineDTO := SourceLineDTO{
|
|
File: src.File,
|
|
Line: line,
|
|
Text: text,
|
|
}
|
|
if off < len(block.Related) {
|
|
lineDTO.Related = lineRangesDTO(block.Related[off])
|
|
}
|
|
if store != nil {
|
|
lineDTO.Comment = store.ForSource(code.Name, src.File, line)
|
|
}
|
|
blockDTO.Lines = append(blockDTO.Lines, lineDTO)
|
|
}
|
|
srcDTO.Blocks = append(srcDTO.Blocks, blockDTO)
|
|
}
|
|
dto.Source = append(dto.Source, srcDTO)
|
|
}
|
|
|
|
for i, inst := range code.Insts {
|
|
goLine := asmLineDTO(i, inst, inst.Text)
|
|
nativeLine := asmLineDTO(i, inst, inst.NativeText)
|
|
if store != nil && inst.Text != "" {
|
|
goLine.Comment = store.ForAsm(code.Name, comments.ViewGoAsm, inst.PC)
|
|
}
|
|
if store != nil && inst.NativeText != "" {
|
|
nativeLine.Comment = store.ForAsm(code.Name, comments.ViewNativeAsm, inst.PC)
|
|
}
|
|
dto.GoAsm = append(dto.GoAsm, goLine)
|
|
dto.NativeAsm = append(dto.NativeAsm, nativeLine)
|
|
}
|
|
|
|
return dto
|
|
}
|
|
|
|
func lineRangesDTO(ranges []disasm.LineRange) []LineRangeDTO {
|
|
if len(ranges) == 0 {
|
|
return nil
|
|
}
|
|
out := make([]LineRangeDTO, 0, len(ranges))
|
|
for _, r := range ranges {
|
|
out = append(out, LineRangeDTO{From: r.From, To: r.To})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func asmLineDTO(index int, inst disasm.Inst, text string) AsmLineDTO {
|
|
line := AsmLineDTO{
|
|
Index: index,
|
|
PC: inst.PC,
|
|
PCHex: comments.FormatPC(inst.PC),
|
|
Text: text,
|
|
File: inst.File,
|
|
Line: inst.Line,
|
|
Call: inst.Call,
|
|
RefPC: inst.RefPC,
|
|
RefOffset: inst.RefOffset,
|
|
}
|
|
if inst.RefPC != 0 {
|
|
line.RefPCHex = comments.FormatPC(inst.RefPC)
|
|
}
|
|
return line
|
|
}
|
|
|
|
func sourceLineExists(code *disasm.Code, file string, line int) bool {
|
|
if code == nil || file == "" || line <= 0 {
|
|
return false
|
|
}
|
|
for _, src := range code.Source {
|
|
if src.File != file && comments.CleanPath(src.File) != comments.CleanPath(file) {
|
|
continue
|
|
}
|
|
for _, block := range src.Blocks {
|
|
if block.From <= line && line < block.From+len(block.Lines) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func asmPCExists(code *disasm.Code, view comments.View, pc uint64) bool {
|
|
if code == nil {
|
|
return false
|
|
}
|
|
for _, inst := range code.Insts {
|
|
switch view {
|
|
case comments.ViewGoAsm:
|
|
if inst.PC == pc && inst.Text != "" {
|
|
return true
|
|
}
|
|
case comments.ViewNativeAsm:
|
|
if inst.PC == pc && inst.NativeText != "" {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|