diff --git a/fuzz/dictionary.txt b/fuzz/dictionary.txt index bb30ef9..73a343c 100644 --- a/fuzz/dictionary.txt +++ b/fuzz/dictionary.txt @@ -1,90 +1,152 @@ +"MD5" +"SHA1" +"SHA256" +"__restart" "accessType" +"accessTypes" "adapterData" "adapterID" "additionalModuleColumns" "address" "addressRange" "algorithm" +"all" "allThreadsContinued" "allThreadsStopped" +"allowPartial" +"always" +"areas" "args" +"argsCanBeInterpretedByShell" "arguments" "attach" +"attachForSuspendedLaunch" "attributeName" "attributes" +"baseClass" +"body" +"boolean" "breakMode" "breakpoint" "breakpointLocations" "breakpoints" +"bytesWritten" +"canPersist" +"canRestart" "cancel" "cancellable" +"cancelled" "capabilities" "category" +"changed" "checksum" "checksums" +"class" "clientID" "clientName" +"clipboard" +"color" "column" "columnsStartAt1" "command" -"completions" "completionTriggerCharacters" +"completions" "condition" +"conditionDescription" +"configuration" "configurationDone" +"console" +"constructor" +"content" "context" "continue" "continued" "count" +"customcolor" "cwd" "data" +"data breakpoint" +"dataBreakpoint" "dataBreakpointInfo" "dataId" "dateTimeStamp" +"deemphasize" "default" "description" +"detail" +"details" "disassemble" "disconnect" +"emphasize" +"end" "endColumn" "endLine" +"entry" +"enum" "env" +"error" "evaluate" "evaluateName" +"event" +"exception" "exceptionBreakpointFilters" +"exceptionId" "exceptionInfo" "exceptionOptions" "exitCode" "exited" "expensive" "expression" -"expression" -"filter" +"external" +"field" +"file" "filter" +"filterId" +"filterOptions" "filters" +"final" "format" "frameId" "fullTypeName" +"function" +"function breakpoint" "goto" "gotoTargets" +"granularity" "group" "hex" +"hitBreakpointIds" "hitCondition" +"hover" "id" +"important" "includeAll" +"indexed" "indexedVariables" -"indexedVariables" +"initialize" "initialized" +"innerClass" "innerException" "instruction" +"instruction breakpoint" "instructionBytes" "instructionCount" "instructionOffset" "instructionPointerReference" +"instructionReference" +"instructions" +"integrated" +"interface" +"internal" +"invalidated" "isLocalProcess" "isOptimized" "isUserCode" +"keyword" "kind" "label" "launch" +"lazy" "length" "levels" "line" @@ -93,27 +155,38 @@ "loadedSource" "loadedSources" "locale" +"locals" "location" "logMessage" +"memory" "memoryReference" "message" +"method" +"mimeType" "module" "moduleCount" "moduleId" "modules" +"mostDerivedClass" "name" +"named" "namedVariables" "names" "negate" +"never" +"new" "next" "noDebug" +"normal" +"notStopped" +"number" "offset" "origin" "output" "parameterNames" -"parameters" "parameterTypes" "parameterValues" +"parameters" "path" "pathFormat" "pause" @@ -121,17 +194,32 @@ "pointerSize" "presentationHint" "preserveFocusHint" +"private" "process" +"processId" "progressEnd" "progressId" "progressStart" "progressUpdate" +"property" +"protected" +"public" +"read" "readMemory" +"readWrite" "reason" +"reference" +"registers" +"removed" +"repl" +"request" "requestId" +"request_seq" "resolveSymbols" +"response" "restart" "restartFrame" +"result" "reverseContinue" "runInTerminal" "scopes" @@ -144,41 +232,66 @@ "setExceptionBreakpoints" "setExpression" "setFunctionBreakpoints" +"setInstructionBreakpoints" "setVariable" +"shellProcessId" "showUser" +"singleThread" +"snippet" "sortText" "source" "sourceModified" "sourceReference" "sources" +"stackFrameId" +"stackFrames" "stackTrace" +"stacks" "start" +"startCollapsed" +"startDebugging" "startFrame" "startMethod" "startModule" +"started" +"statement" +"stderr" +"stdout" +"step" "stepBack" "stepIn" "stepInTargets" "stepOut" "stopped" +"string" +"subtle" +"success" +"supportSuspendDebuggee" +"supportTerminateDebuggee" "supportedChecksumAlgorithms" +"supportsArgsCanBeInterpretedByShell" "supportsBreakpointLocationsRequest" "supportsCancelRequest" "supportsClipboardContext" "supportsCompletionsRequest" +"supportsCondition" "supportsConditionalBreakpoints" "supportsConfigurationDoneRequest" "supportsDataBreakpoints" "supportsDelayedStackTraceLoading" "supportsDisassembleRequest" "supportsEvaluateForHovers" +"supportsExceptionFilterOptions" "supportsExceptionInfoRequest" "supportsExceptionOptions" "supportsFunctionBreakpoints" "supportsGotoTargetsRequest" "supportsHitConditionalBreakpoints" +"supportsInstructionBreakpoints" +"supportsInvalidatedEvent" "supportsLoadedSourcesRequest" "supportsLogPoints" +"supportsMemoryEvent" "supportsMemoryReferences" "supportsModulesRequest" "supportsProgressReporting" @@ -188,38 +301,57 @@ "supportsRunInTerminalRequest" "supportsSetExpression" "supportsSetVariable" +"supportsSingleThreadExecutionRequests" +"supportsStartDebuggingRequest" "supportsStepBack" "supportsStepInTargetsRequest" +"supportsSteppingGranularity" "supportsTerminateRequest" "supportsTerminateThreadsRequest" "supportsValueFormattingOptions" "supportsVariablePaging" "supportsVariableType" -"supportTerminateDebuggee" +"supportsWriteMemoryRequest" +"suspendDebuggee" "symbol" "symbolFilePath" "symbolStatus" "systemProcessId" "targetId" +"targets" +"telemetry" "terminate" -"terminated" "terminateDebuggee" "terminateThreads" +"terminated" "text" "thread" "threadId" "threadIds" "threads" +"timestamp" "title" -"title" +"totalFrames" +"totalModules" "type" "typeName" +"unhandled" +"unit" +"unixTimestampUTC" +"unreadableBytes" +"uri" "url" "urlLabel" +"userUnhandled" "value" +"variable" "variables" "variablesReference" "verified" "version" +"virtual" "visibility" -"width" \ No newline at end of file +"watch" +"width" +"write" +"writeMemory" \ No newline at end of file diff --git a/fuzz/fuzz.cpp b/fuzz/fuzz.cpp index 6f459be..02a21cc 100644 --- a/fuzz/fuzz.cpp +++ b/fuzz/fuzz.cpp @@ -22,6 +22,8 @@ #include "dap/protocol.h" #include "dap/session.h" +#include "fuzz.h" + #include #include @@ -52,53 +54,6 @@ class Event { } // namespace -// List of requests that we handle for fuzzing. -#define DAP_REQUEST_LIST() \ - DAP_REQUEST(dap::AttachRequest, dap::AttachResponse) \ - DAP_REQUEST(dap::BreakpointLocationsRequest, \ - dap::BreakpointLocationsResponse) \ - DAP_REQUEST(dap::CancelRequest, dap::CancelResponse) \ - DAP_REQUEST(dap::CompletionsRequest, dap::CompletionsResponse) \ - DAP_REQUEST(dap::ConfigurationDoneRequest, dap::ConfigurationDoneResponse) \ - DAP_REQUEST(dap::ContinueRequest, dap::ContinueResponse) \ - DAP_REQUEST(dap::DataBreakpointInfoRequest, dap::DataBreakpointInfoResponse) \ - DAP_REQUEST(dap::DisassembleRequest, dap::DisassembleResponse) \ - DAP_REQUEST(dap::DisconnectRequest, dap::DisconnectResponse) \ - DAP_REQUEST(dap::EvaluateRequest, dap::EvaluateResponse) \ - DAP_REQUEST(dap::ExceptionInfoRequest, dap::ExceptionInfoResponse) \ - DAP_REQUEST(dap::GotoRequest, dap::GotoResponse) \ - DAP_REQUEST(dap::GotoTargetsRequest, dap::GotoTargetsResponse) \ - DAP_REQUEST(dap::InitializeRequest, dap::InitializeResponse) \ - DAP_REQUEST(dap::LaunchRequest, dap::LaunchResponse) \ - DAP_REQUEST(dap::LoadedSourcesRequest, dap::LoadedSourcesResponse) \ - DAP_REQUEST(dap::ModulesRequest, dap::ModulesResponse) \ - DAP_REQUEST(dap::NextRequest, dap::NextResponse) \ - DAP_REQUEST(dap::PauseRequest, dap::PauseResponse) \ - DAP_REQUEST(dap::ReadMemoryRequest, dap::ReadMemoryResponse) \ - DAP_REQUEST(dap::RestartFrameRequest, dap::RestartFrameResponse) \ - DAP_REQUEST(dap::RestartRequest, dap::RestartResponse) \ - DAP_REQUEST(dap::ReverseContinueRequest, dap::ReverseContinueResponse) \ - DAP_REQUEST(dap::RunInTerminalRequest, dap::RunInTerminalResponse) \ - DAP_REQUEST(dap::ScopesRequest, dap::ScopesResponse) \ - DAP_REQUEST(dap::SetBreakpointsRequest, dap::SetBreakpointsResponse) \ - DAP_REQUEST(dap::SetDataBreakpointsRequest, dap::SetDataBreakpointsResponse) \ - DAP_REQUEST(dap::SetExceptionBreakpointsRequest, \ - dap::SetExceptionBreakpointsResponse) \ - DAP_REQUEST(dap::SetExpressionRequest, dap::SetExpressionResponse) \ - DAP_REQUEST(dap::SetFunctionBreakpointsRequest, \ - dap::SetFunctionBreakpointsResponse) \ - DAP_REQUEST(dap::SetVariableRequest, dap::SetVariableResponse) \ - DAP_REQUEST(dap::SourceRequest, dap::SourceResponse) \ - DAP_REQUEST(dap::StackTraceRequest, dap::StackTraceResponse) \ - DAP_REQUEST(dap::StepBackRequest, dap::StepBackResponse) \ - DAP_REQUEST(dap::StepInRequest, dap::StepInResponse) \ - DAP_REQUEST(dap::StepInTargetsRequest, dap::StepInTargetsResponse) \ - DAP_REQUEST(dap::StepOutRequest, dap::StepOutResponse) \ - DAP_REQUEST(dap::TerminateRequest, dap::TerminateResponse) \ - DAP_REQUEST(dap::TerminateThreadsRequest, dap::TerminateThreadsResponse) \ - DAP_REQUEST(dap::ThreadsRequest, dap::ThreadsResponse) \ - DAP_REQUEST(dap::VariablesRequest, dap::VariablesResponse) - // Fuzzing main function. // See http://llvm.org/docs/LibFuzzer.html for details. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/fuzz/fuzz.h b/fuzz/fuzz.h new file mode 100644 index 0000000..a35800c --- /dev/null +++ b/fuzz/fuzz.h @@ -0,0 +1,75 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Generated with protocol_gen.go -- do not edit this file. +// go run scripts/protocol_gen/protocol_gen.go +// +// DAP version 1.59.0 + +#ifndef dap_fuzzer_h +#define dap_fuzzer_h + +#include "dap/protocol.h" + +#define DAP_REQUEST_LIST() \ + DAP_REQUEST(dap::AttachRequest, dap::AttachResponse) \ + DAP_REQUEST(dap::BreakpointLocationsRequest, \ + dap::BreakpointLocationsResponse) \ + DAP_REQUEST(dap::CancelRequest, dap::CancelResponse) \ + DAP_REQUEST(dap::CompletionsRequest, dap::CompletionsResponse) \ + DAP_REQUEST(dap::ConfigurationDoneRequest, dap::ConfigurationDoneResponse) \ + DAP_REQUEST(dap::ContinueRequest, dap::ContinueResponse) \ + DAP_REQUEST(dap::DataBreakpointInfoRequest, dap::DataBreakpointInfoResponse) \ + DAP_REQUEST(dap::DisassembleRequest, dap::DisassembleResponse) \ + DAP_REQUEST(dap::DisconnectRequest, dap::DisconnectResponse) \ + DAP_REQUEST(dap::EvaluateRequest, dap::EvaluateResponse) \ + DAP_REQUEST(dap::ExceptionInfoRequest, dap::ExceptionInfoResponse) \ + DAP_REQUEST(dap::GotoRequest, dap::GotoResponse) \ + DAP_REQUEST(dap::GotoTargetsRequest, dap::GotoTargetsResponse) \ + DAP_REQUEST(dap::InitializeRequest, dap::InitializeResponse) \ + DAP_REQUEST(dap::LaunchRequest, dap::LaunchResponse) \ + DAP_REQUEST(dap::LoadedSourcesRequest, dap::LoadedSourcesResponse) \ + DAP_REQUEST(dap::ModulesRequest, dap::ModulesResponse) \ + DAP_REQUEST(dap::NextRequest, dap::NextResponse) \ + DAP_REQUEST(dap::PauseRequest, dap::PauseResponse) \ + DAP_REQUEST(dap::ReadMemoryRequest, dap::ReadMemoryResponse) \ + DAP_REQUEST(dap::RestartFrameRequest, dap::RestartFrameResponse) \ + DAP_REQUEST(dap::RestartRequest, dap::RestartResponse) \ + DAP_REQUEST(dap::ReverseContinueRequest, dap::ReverseContinueResponse) \ + DAP_REQUEST(dap::RunInTerminalRequest, dap::RunInTerminalResponse) \ + DAP_REQUEST(dap::ScopesRequest, dap::ScopesResponse) \ + DAP_REQUEST(dap::SetBreakpointsRequest, dap::SetBreakpointsResponse) \ + DAP_REQUEST(dap::SetDataBreakpointsRequest, dap::SetDataBreakpointsResponse) \ + DAP_REQUEST(dap::SetExceptionBreakpointsRequest, \ + dap::SetExceptionBreakpointsResponse) \ + DAP_REQUEST(dap::SetExpressionRequest, dap::SetExpressionResponse) \ + DAP_REQUEST(dap::SetFunctionBreakpointsRequest, \ + dap::SetFunctionBreakpointsResponse) \ + DAP_REQUEST(dap::SetInstructionBreakpointsRequest, \ + dap::SetInstructionBreakpointsResponse) \ + DAP_REQUEST(dap::SetVariableRequest, dap::SetVariableResponse) \ + DAP_REQUEST(dap::SourceRequest, dap::SourceResponse) \ + DAP_REQUEST(dap::StackTraceRequest, dap::StackTraceResponse) \ + DAP_REQUEST(dap::StartDebuggingRequest, dap::StartDebuggingResponse) \ + DAP_REQUEST(dap::StepBackRequest, dap::StepBackResponse) \ + DAP_REQUEST(dap::StepInRequest, dap::StepInResponse) \ + DAP_REQUEST(dap::StepInTargetsRequest, dap::StepInTargetsResponse) \ + DAP_REQUEST(dap::StepOutRequest, dap::StepOutResponse) \ + DAP_REQUEST(dap::TerminateRequest, dap::TerminateResponse) \ + DAP_REQUEST(dap::TerminateThreadsRequest, dap::TerminateThreadsResponse) \ + DAP_REQUEST(dap::ThreadsRequest, dap::ThreadsResponse) \ + DAP_REQUEST(dap::VariablesRequest, dap::VariablesResponse) \ + DAP_REQUEST(dap::WriteMemoryRequest, dap::WriteMemoryResponse) + +#endif // dap_fuzzer_h diff --git a/tools/protocol_gen/protocol_gen.go b/tools/protocol_gen/protocol_gen.go index 4f6b9ea..c5e112c 100644 --- a/tools/protocol_gen/protocol_gen.go +++ b/tools/protocol_gen/protocol_gen.go @@ -93,6 +93,19 @@ namespace dap { ` cppEpilogue = `} // namespace dap +` + fuzzerHeaderPrologue = commonPrologue + ` +#ifndef dap_fuzzer_h +#define dap_fuzzer_h + +#include "dap/protocol.h" + +#define DAP_REQUEST_LIST() \ +` + + fuzzerHeaderEpilogue = ` + +#endif // dap_fuzzer_h ` ) @@ -187,6 +200,7 @@ type cppField struct { ty cppType name string optional bool + enumVals []string } // cppType is an interface for all C++ generated types @@ -207,6 +221,10 @@ type cppType interface { WriteHeader(w io.Writer) // WriteHeader() writes the type definition to the given .cpp file writer WriteCPP(w io.Writer) + // WriteFuzzerH() writes the fuzzer DAP_REQUEST() macro to the given .h writer + WriteFuzzerH(w io.Writer) + // GetFuzzerNames() returns a list of the protocol name, the fields, and field enum values for this type + GetFuzzerNames() []string } // cppStruct implements the cppType interface, describing a C++ structure @@ -295,11 +313,54 @@ func (s *cppStruct) WriteCPP(w io.Writer) { io.WriteString(w, ");\n\n") } +func (s *cppStruct) WriteFuzzerH(header io.Writer) { + // only write fuzzer macros for Request types + if s.base != "Request" { + return + } + + io.WriteString(header, "DAP_REQUEST(dap::") + io.WriteString(header, s.name) + io.WriteString(header, ", dap::") + + responseType := "" + + // check typedefs for response + for _, t := range s.typedefs { + if t.from == "Response" { + responseType = t.to.Name() + } + } + + // if no response, throw an error + if responseType == "" { + panic("No corresponding response type found for " + s.name) + } + + io.WriteString(header, responseType) + io.WriteString(header, ") \\\n") +} + +func (s *cppStruct) GetFuzzerNames() []string { + ret := []string{} + if s.protoname != "" { + ret = append(ret, s.protoname) + } + for _, f := range s.fields { + ret = append(ret, f.name) + if (f.enumVals != nil) && (len(f.enumVals) > 0) { + ret = append(ret, f.enumVals...) + } + } + return ret +} + // cppStruct implements the cppType interface, describing a C++ typedef type cppTypedef struct { - from string // Name of the typedef - to cppType // Target of the typedef - desc string // Description + from string // Name of the typedef + to cppType // Target of the typedef + desc string // Description + enumVals []string // Enum values } func (ty *cppTypedef) Name() string { return ty.from } @@ -320,7 +381,11 @@ func (ty *cppTypedef) WriteHeader(w io.Writer) { io.WriteString(w, ty.to.Name()) io.WriteString(w, ";\n\n") } -func (ty *cppTypedef) WriteCPP(w io.Writer) {} +func (ty *cppTypedef) WriteCPP(w io.Writer) {} +func (ty *cppTypedef) WriteFuzzerH(w io.Writer) {} +func (s *cppTypedef) GetFuzzerNames() []string { + return s.enumVals +} // cppStruct implements the cppType interface, describing a basic C++ type type cppBasicType struct { @@ -330,13 +395,44 @@ type cppBasicType struct { defaultValue string // Default value for fields of this type } -func (ty *cppBasicType) Name() string { return ty.name } -func (ty *cppBasicType) Dependencies() []cppType { return ty.deps } -func (ty *cppBasicType) File() cppTargetFile { return types } -func (ty *cppBasicType) Description() string { return ty.desc } -func (ty *cppBasicType) DefaultValue() string { return ty.defaultValue } -func (ty *cppBasicType) WriteHeader(w io.Writer) {} -func (ty *cppBasicType) WriteCPP(w io.Writer) {} +func (ty *cppBasicType) Name() string { return ty.name } +func (ty *cppBasicType) Dependencies() []cppType { return ty.deps } +func (ty *cppBasicType) File() cppTargetFile { return types } +func (ty *cppBasicType) Description() string { return ty.desc } +func (ty *cppBasicType) DefaultValue() string { return ty.defaultValue } +func (ty *cppBasicType) WriteHeader(w io.Writer) {} +func (ty *cppBasicType) WriteCPP(w io.Writer) {} +func (ty *cppBasicType) WriteFuzzerH(w io.Writer) {} +func (ty *cppBasicType) GetFuzzerNames() []string { + return []string{} +} + +func stringify(s string) string { + return "\"" + s + "\"" +} + +func stringifyArray(s []string) []string { + ret := []string{} + if s == nil { + return ret + } + for _, v := range s { + ret = append(ret, stringify(v)) + } + return ret +} + +func removeDuplicateStr(strSlice []string) []string { + allKeys := make(map[string]bool) + list := []string{} + for _, item := range strSlice { + if _, value := allKeys[item]; !value { + allKeys[item] = true + list = append(list, item) + } + } + return list +} // sanitize() returns the given identifier transformed into a legal C++ identifier func sanitize(s string) string { @@ -455,11 +551,19 @@ func (r *root) buildRootStruct(ty *cppStruct, def *definition) error { optional := !required[propName] desc := appendEnumDetails(property.Description, property.OpenEnum, property.ClosedEnum) + enumVals := []string{} + if len(property.ClosedEnum) > 0 { + enumVals = append(enumVals, property.ClosedEnum...) + } + if len(property.OpenEnum) > 0 { + enumVals = append(enumVals, property.OpenEnum...) + } ty.fields = append(ty.fields, cppField{ desc: desc, ty: propTy, name: propName, optional: optional, + enumVals: enumVals, }) ty.deps = append(ty.deps, propTy) @@ -632,6 +736,16 @@ func (r *root) buildTypes() ([]cppType, error) { from: entry.name, to: enumTy, desc: enumTy.Description(), + enumVals: func() []string { + ret := []string{} + if len(entry.def.ClosedEnum) > 0 { + ret = entry.def.ClosedEnum + } + if len(entry.def.OpenEnum) > 0 { + ret = append(ret, entry.def.OpenEnum...) + } + return ret + }(), } entry.def.cppType = ty out = append(out, entry.def.cppType) @@ -680,8 +794,8 @@ func run() error { return fmt.Errorf("Failed to load JSON file from '%v': %w", protocolURL, err) } - hPath, cppPaths, cMakeListsPath := outputPaths() - if err := emitFiles(&protocol, hPath, cppPaths, pkg.Version); err != nil { + hPath, cppPaths, cMakeListsPath, fuzzerhPath, fuzzerDictPath := outputPaths() + if err := emitFiles(&protocol, hPath, cppPaths, fuzzerhPath, fuzzerDictPath, pkg.Version); err != nil { return fmt.Errorf("Failed to emit files: %w", err) } @@ -698,6 +812,9 @@ func run() error { return fmt.Errorf("Failed to run clang-format on '%v':\n%v\n%w", p, string(out), err) } } + if out, err := exec.Command(clangfmt, "-i", fuzzerhPath).CombinedOutput(); err != nil { + return fmt.Errorf("Failed to run clang-format on '%v':\n%v\n%w", fuzzerhPath, string(out), err) + } } else { fmt.Printf("clang-format not found on PATH. Please format before committing.") } @@ -725,7 +842,7 @@ func updateCMakePackageVersion(cMakeListsPath string, version string) error { // emitFiles() opens each of the C++ files, generates the cppType definitions // from the schema root, then writes the types to the C++ files in dependency // order. -func emitFiles(r *root, hPath string, cppPaths map[cppTargetFile]string, version string) error { +func emitFiles(r *root, hPath string, cppPaths map[cppTargetFile]string, fuzzerhPath string, fuzzerDictPath string, version string) error { h, err := os.Create(hPath) if err != nil { return err @@ -741,10 +858,19 @@ func emitFiles(r *root, hPath string, cppPaths map[cppTargetFile]string, version defer f.Close() } + fuzzer_h, err := os.Create(fuzzerhPath) + if err != nil { + return err + } + fuzzerDict, err := os.Create(fuzzerDictPath) + if err != nil { + return err + } h.WriteString(strings.ReplaceAll(headerPrologue, versionTag, version)) for _, f := range cppFiles { f.WriteString(strings.ReplaceAll(cppPrologue, versionTag, version)) } + fuzzer_h.WriteString(strings.ReplaceAll(fuzzerHeaderPrologue, versionTag, version)) types, err := r.buildTypes() if err != nil { @@ -757,6 +883,17 @@ func emitFiles(r *root, hPath string, cppPaths map[cppTargetFile]string, version } seen := map[string]bool{} + // Prepopulate the names list with the types that are not generated from the schema. + ProtocolMessageFuzzerNames := []string{"seq", "type", "request", "response", "event"} + RequestMessageFuzzerNames := []string{"request", "type", "command", "arguments"} + EventMessageFuzzerNames := []string{"event", "type", "event", "body"} + ResponseMessageFuzzerNames := []string{"response", "type", "request_seq", "success", "command", "message", "body", + "cancelled", "notStopped"} + fuzzerNames := []string{} + fuzzerNames = append(fuzzerNames, ProtocolMessageFuzzerNames...) + fuzzerNames = append(fuzzerNames, RequestMessageFuzzerNames...) + fuzzerNames = append(fuzzerNames, EventMessageFuzzerNames...) + fuzzerNames = append(fuzzerNames, ResponseMessageFuzzerNames...) var emit func(cppType) error emit = func(ty cppType) error { name := ty.Name() @@ -771,6 +908,11 @@ func emitFiles(r *root, hPath string, cppPaths map[cppTargetFile]string, version } ty.WriteHeader(h) ty.WriteCPP(cppFiles[ty.File()]) + ty.WriteFuzzerH(fuzzer_h) + + // collect protoname, field names, and field enum values for dictionary + fuzzerNames = append(fuzzerNames, ty.GetFuzzerNames()...) + return nil } @@ -785,10 +927,22 @@ func emitFiles(r *root, hPath string, cppPaths map[cppTargetFile]string, version } } + // sort names alphabetically + sort.Strings(fuzzerNames) + // remove duplicates + fuzzerNames = removeDuplicateStr(fuzzerNames) + // append "" to each name + fuzzerNames = stringifyArray(fuzzerNames) + dict := strings.Join(fuzzerNames, "\n") + if _, err := io.WriteString(fuzzerDict, dict); err != nil { + return err + } + h.WriteString(headerEpilogue) for _, f := range cppFiles { f.WriteString(cppEpilogue) } + fuzzer_h.WriteString(fuzzerHeaderEpilogue) return nil } @@ -811,7 +965,7 @@ func loadJSONFile(url string, obj interface{}) error { } // outputPaths() returns a path to the target C++ .h file and .cpp files, and the CMakeLists.txt -func outputPaths() (string, cppTargetFilePaths, string) { +func outputPaths() (string, cppTargetFilePaths, string, string, string) { _, thisFile, _, _ := runtime.Caller(1) thisDir := path.Dir(thisFile) h := path.Join(thisDir, "../../include/dap/protocol.h") @@ -822,5 +976,7 @@ func outputPaths() (string, cppTargetFilePaths, string) { types: path.Join(thisDir, "../../src/protocol_types.cpp"), } CMakeLists := path.Join(thisDir, "../../CMakeLists.txt") - return h, cpp, CMakeLists + fuzzer_h := path.Join(thisDir, "../../fuzz/fuzz.h") + fuzzer_dict := path.Join(thisDir, "../../fuzz/dictionary.txt") + return h, cpp, CMakeLists, fuzzer_h, fuzzer_dict }