1// Copyright 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package rust
16
17import (
18	"android/soong/android"
19	"android/soong/cc"
20	"android/soong/fuzz"
21	"android/soong/rust/config"
22	"path/filepath"
23)
24
25func init() {
26	android.RegisterModuleType("rust_fuzz", RustFuzzFactory)
27	android.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
28}
29
30type fuzzDecorator struct {
31	*binaryDecorator
32
33	fuzzPackagedModule  fuzz.FuzzPackagedModule
34	sharedLibraries     android.RuleBuilderInstalls
35	installedSharedDeps []string
36}
37
38var _ compiler = (*fuzzDecorator)(nil)
39
40// rust_binary produces a binary that is runnable on a device.
41func RustFuzzFactory() android.Module {
42	module, _ := NewRustFuzz(android.HostAndDeviceSupported)
43	return module.Init()
44}
45
46func RustFuzzHostFactory() android.Module {
47	module, _ := NewRustFuzz(android.HostSupported)
48	return module.Init()
49}
50
51func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) {
52	module, binary := NewRustBinary(hod)
53	fuzz := &fuzzDecorator{
54		binaryDecorator: binary,
55	}
56
57	// Change the defaults for the binaryDecorator's baseCompiler
58	fuzz.binaryDecorator.baseCompiler.dir = "fuzz"
59	fuzz.binaryDecorator.baseCompiler.dir64 = "fuzz"
60	fuzz.binaryDecorator.baseCompiler.location = InstallInData
61	module.sanitize.SetSanitizer(cc.Fuzzer, true)
62
63	// The fuzzer runtime is not present for darwin or bionic host modules, so disable rust_fuzz modules for these.
64	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
65
66		extraProps := struct {
67			Target struct {
68				Darwin struct {
69					Enabled *bool
70				}
71				Linux_bionic struct {
72					Enabled *bool
73				}
74			}
75		}{}
76		extraProps.Target.Darwin.Enabled = cc.BoolPtr(false)
77		extraProps.Target.Linux_bionic.Enabled = cc.BoolPtr(false)
78		ctx.AppendProperties(&extraProps)
79	})
80
81	module.compiler = fuzz
82	return module, fuzz
83}
84
85func (fuzzer *fuzzDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
86	flags = fuzzer.binaryDecorator.compilerFlags(ctx, flags)
87
88	// `../lib` for installed fuzz targets (both host and device), and `./lib` for fuzz target packages.
89	flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
90
91	if ctx.InstallInVendor() {
92		flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`)
93	} else {
94		flags.LinkFlags = append(flags.LinkFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
95
96	}
97	return flags
98}
99
100func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
101	if libFuzzerRuntimeLibrary := config.LibFuzzerRuntimeLibrary(ctx.toolchain()); libFuzzerRuntimeLibrary != "" {
102		deps.StaticLibs = append(deps.StaticLibs, libFuzzerRuntimeLibrary)
103	}
104	deps.SharedLibs = append(deps.SharedLibs, "libc++")
105	deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys")
106
107	deps = fuzzer.binaryDecorator.compilerDeps(ctx, deps)
108
109	return deps
110}
111
112func (fuzzer *fuzzDecorator) compilerProps() []interface{} {
113	return append(fuzzer.binaryDecorator.compilerProps(),
114		&fuzzer.fuzzPackagedModule.FuzzProperties)
115}
116
117func (fuzzer *fuzzDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
118
119	out := fuzzer.binaryDecorator.compile(ctx, flags, deps)
120
121	return out
122}
123
124func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage {
125	return RlibLinkage
126}
127
128func (fuzzer *fuzzDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
129	return rlibAutoDep
130}
131
132func (fuzz *fuzzDecorator) install(ctx ModuleContext) {
133	fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule, pctx)
134
135	installBase := "fuzz"
136
137	// Grab the list of required shared libraries.
138	fuzz.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx)
139
140	for _, ruleBuilderInstall := range fuzz.sharedLibraries {
141		install := ruleBuilderInstall.To
142
143		fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
144			cc.SharedLibraryInstallLocation(
145				install, ctx.Host(), ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String()))
146
147		// Also add the dependency on the shared library symbols dir.
148		if !ctx.Host() {
149			fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
150				cc.SharedLibrarySymbolsInstallLocation(install, ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String()))
151		}
152	}
153
154	var fuzzData []android.DataPath
155	for _, d := range fuzz.fuzzPackagedModule.Corpus {
156		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true})
157	}
158
159	for _, d := range fuzz.fuzzPackagedModule.Data {
160		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, RelativeInstallPath: "data"})
161	}
162
163	if d := fuzz.fuzzPackagedModule.Dictionary; d != nil {
164		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, WithoutRel: true})
165	}
166
167	if d := fuzz.fuzzPackagedModule.Config; d != nil {
168		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, WithoutRel: true})
169	}
170
171	fuzz.binaryDecorator.baseCompiler.dir = filepath.Join(
172		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
173	fuzz.binaryDecorator.baseCompiler.dir64 = filepath.Join(
174		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
175	fuzz.binaryDecorator.baseCompiler.installTestData(ctx, fuzzData)
176
177	fuzz.binaryDecorator.baseCompiler.install(ctx)
178
179}
180