diff --git a/internal/parsers/elf/meta.go b/internal/parsers/elf/meta.go
new file mode 100644
index 0000000..0557a3c
--- /dev/null
+++ b/internal/parsers/elf/meta.go
@@ -0,0 +1,9 @@
+package elf
+
+import "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
+
+var name = "elf"
+
+func init() {
+	stage.RegisterParser(name, &Elf{})
+}
diff --git a/internal/parsers/elf/model.go b/internal/parsers/elf/model.go
new file mode 100644
index 0000000..a8e7960
--- /dev/null
+++ b/internal/parsers/elf/model.go
@@ -0,0 +1,41 @@
+package elf
+
+type Toplevel struct {
+	Title   string   `json:"title"`
+	Modules []Module `json:"modules"`
+}
+
+type Module struct {
+	Entries   []Entry `json:"entries"`
+	DebugInfo string  `json:"debug_info"`
+}
+
+type Entry []any
+
+type Report struct {
+	File  string `json:"file"`
+	Name  string `json:"name"`
+	Cases []Case `json:"cases" mapstructure:"cases"`
+}
+
+type Case struct {
+	Binders        []Binder `mapstructure:"binders"`
+	Context        *string  `mapstructure:"context"`
+	Depths         *int     `mapstructure:"depths"`
+	Code           *string  `mapstructure:"code"`
+	Plain          *int     `mapstructure:"plain"`
+	Weighed        *float64 `mapstructure:"weighed"`
+	Detail         *string  `mapstructure:"detail"`
+	SimilarityRate float64  `mapstructure:"similarity_rate"`
+	Sources        []Source `mapstructure:"srcs"`
+}
+
+type Binder struct {
+	Binder string `json:"binder"`
+	Pos    string `json:"pos"`
+}
+
+type Source struct {
+	Context string `json:"context"`
+	Code    string `json:"code"`
+}
diff --git a/internal/parsers/elf/parser.go b/internal/parsers/elf/parser.go
new file mode 100644
index 0000000..96e4abd
--- /dev/null
+++ b/internal/parsers/elf/parser.go
@@ -0,0 +1,96 @@
+package elf
+
+import (
+	"encoding/json"
+	"fmt"
+	"log/slog"
+
+	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
+	"github.com/criyle/go-judge/envexec"
+	"github.com/mitchellh/mapstructure"
+)
+
+type Conf struct {
+	Score   int
+	Comment string
+}
+
+type Elf struct{}
+
+func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
+	stdout := executorResult.Files["stdout"]
+	stderr := executorResult.Files["stderr"]
+	if executorResult.Status != stage.Status(envexec.StatusAccepted) {
+		return stage.ParserResult{
+			Score: 0,
+			Comment: fmt.Sprintf(
+				"Unexpected executor status: %s.\nStderr: %s",
+				executorResult.Status, stderr,
+			),
+		}
+	}
+	var topLevel Toplevel
+	err := json.Unmarshal([]byte(stdout), &topLevel)
+	if err != nil {
+		return stage.ParserResult{
+			Score:   0,
+			Comment: fmt.Sprintf("Failed to parse result: %s", err),
+		}
+	}
+	for _, module := range topLevel.Modules {
+		for _, entry := range module.Entries {
+			kind := entry[0].(string)
+			report := Report{}
+			err := mapstructure.Decode(entry[1], &report)
+			if err != nil {
+				slog.Error("elf parse", "mapstructure decode err", err)
+			}
+			slog.Debug("elf parse", "report file", report.File)
+			slog.Debug("elf parse", "report name", report.Name)
+			slog.Debug("elf parse", "report kind", kind)
+			for _, caseObj := range report.Cases {
+				switch kind {
+				case "ParenDep":
+					slog.Debug("elf parse", "binders", caseObj.Binders)
+					slog.Debug("elf parse", "context", caseObj.Context)
+					slog.Debug("elf parse", "depths", caseObj.Depths)
+					slog.Debug("elf parse", "code", caseObj.Code)
+				case "CodeLen":
+					slog.Debug("elf parse", "binders", caseObj.Binders)
+					slog.Debug("elf parse", "context", caseObj.Context)
+					slog.Debug("elf parse", "plain", caseObj.Plain)
+					slog.Debug("elf parse", "weighed", caseObj.Weighed)
+					slog.Debug("elf parse", "code", caseObj.Code)
+				case "OverArity":
+					slog.Debug("elf parse", "binders", caseObj.Binders)
+					slog.Debug("elf parse", "context", caseObj.Context)
+					slog.Debug("elf parse", "detail", caseObj.Detail)
+					slog.Debug("elf parse", "code", caseObj.Code)
+				case "CodeDup":
+					slog.Debug("elf parse", "similarity rate", caseObj.SimilarityRate)
+					for _, source := range caseObj.Sources {
+						slog.Debug("elf parse", "context", source.Context, "code", source.Code)
+					}
+				}
+			}
+		}
+	}
+	return stage.ParserResult{
+		Score:   conf.Score,
+		Comment: conf.Comment,
+	}
+}
+
+func (*Elf) Run(results []stage.ExecutorResult, confAny any) (
+	[]stage.ParserResult, bool, error,
+) {
+	conf, err := stage.DecodeConf[Conf](confAny)
+	if err != nil {
+		return nil, true, err
+	}
+	var res []stage.ParserResult
+	for _, result := range results {
+		res = append(res, Parse(result, *conf))
+	}
+	return res, false, nil
+}