Add ELF binary package cataloger (#2396)

* feat Adds Elf package catalogger

Signed-off-by: Brian Ebarb <ebarb.brian@gmail.com>

* Add test fixtures for elf package

Signed-off-by: Colleen Divers <colleen.divers@gmail.com>

* bump JSON schema to v16.0.6 + expand test fixtures

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* less verbose logging

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* remove dead test code

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* remove unreleated swift change

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Brian Ebarb <ebarb.brian@gmail.com>
Signed-off-by: Colleen Divers <colleen.divers@gmail.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Colleen Divers <colleen.divers@gmail.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
brian-ebarb 2024-03-14 10:16:03 -05:00 committed by GitHub
parent 7ab6fc3fe4
commit 6a2517b5d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 2980 additions and 6 deletions

View file

@ -3,5 +3,5 @@ package internal
const (
// JSONSchemaVersion is the current schema version output by the JSON encoder
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
JSONSchemaVersion = "16.0.5"
JSONSchemaVersion = "16.0.6"
)

View file

@ -117,6 +117,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
},
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary",
),
newSimplePackageTaskFactory(binary.NewELFPackageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary", "elf-package"),
newSimplePackageTaskFactory(githubactions.NewActionUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
newSimplePackageTaskFactory(githubactions.NewWorkflowUsageCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "github", "github-actions"),
newPackageTaskFactory(

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.0.5/document",
"$id": "anchore.io/schema/syft/json/16.0.6/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
@ -630,6 +630,26 @@
"dso"
]
},
"ElfBinaryPackageNoteJsonPayload": {
"properties": {
"type": {
"type": "string"
},
"vendor": {
"type": "string"
},
"system": {
"type": "string"
},
"sourceRepo": {
"type": "string"
},
"commit": {
"type": "string"
}
},
"type": "object"
},
"ElixirMixLockEntry": {
"properties": {
"name": {
@ -1425,6 +1445,9 @@
{
"$ref": "#/$defs/DpkgDbEntry"
},
{
"$ref": "#/$defs/ElfBinaryPackageNoteJsonPayload"
},
{
"$ref": "#/$defs/ElixirMixLockEntry"
},

View file

@ -19,6 +19,7 @@ func AllTypes() []any {
pkg.DotnetDepsEntry{},
pkg.DotnetPortableExecutableEntry{},
pkg.DpkgDBEntry{},
pkg.ELFBinaryPackageNoteJSONPayload{},
pkg.ElixirMixLockEntry{},
pkg.ErlangRebarLockEntry{},
pkg.GolangBinaryBuildinfoEntry{},

View file

@ -74,6 +74,7 @@ var jsonTypes = makeJSONTypes(
jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"),
jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"),
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
jsonNames(pkg.ELFBinaryPackageNoteJSONPayload{}, "elf-binary-package-note-json-payload"),
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
jsonNames(pkg.GolangBinaryBuildinfoEntry{}, "go-module-buildinfo-entry", "GolangBinMetadata", "GolangMetadata"),
jsonNames(pkg.GolangModuleEntry{}, "go-module-entry", "GolangModMetadata"),

View file

@ -12,3 +12,12 @@ type ClassifierMatch struct {
Classifier string `mapstructure:"Classifier" json:"classifier"`
Location file.Location `mapstructure:"Location" json:"location"`
}
// ELFBinaryPackageNoteJSONPayload Represents metadata captured from the .note.package section of the binary
type ELFBinaryPackageNoteJSONPayload struct {
Type string `json:"type,omitempty"`
Vendor string `json:"vendor,omitempty"`
System string `json:"system,omitempty"`
SourceRepo string `json:"sourceRepo,omitempty"`
Commit string `json:"commit,omitempty"`
}

View file

@ -1,4 +1,4 @@
# Adding tests for the Binary cataloger
# Adding tests for the Binary classifier cataloger
> [!TIP]
> **TL;DR** to add a test for a new classifier:

View file

@ -125,7 +125,7 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
matchMetadata := internal.MatchNamedCaptureGroups(tmplPattern, string(contents))
p := newPackage(classifier, location, matchMetadata)
p := newClassifierPackage(classifier, location, matchMetadata)
if p == nil {
return nil, nil
}
@ -144,7 +144,7 @@ func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
matchMetadata := internal.MatchNamedCaptureGroups(pat, string(contents))
p := newPackage(classifier, location, matchMetadata)
p := newClassifierPackage(classifier, location, matchMetadata)
if p == nil {
return nil, nil
}

View file

@ -11,7 +11,7 @@ import (
var emptyPURL = packageurl.PackageURL{}
func newPackage(classifier Classifier, location file.Location, matchMetadata map[string]string) *pkg.Package {
func newClassifierPackage(classifier Classifier, location file.Location, matchMetadata map[string]string) *pkg.Package {
version, ok := matchMetadata["version"]
if !ok {
return nil

View file

@ -0,0 +1,35 @@
package binary
import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)
func newELFPackage(metadata elfBinaryPackageNotes, locations file.LocationSet, licenses []pkg.License) pkg.Package {
p := pkg.Package{
Name: metadata.Name,
Version: metadata.Version,
Licenses: pkg.NewLicenseSet(licenses...),
PURL: packageURL(metadata),
Type: pkg.BinaryPkg,
Locations: locations,
Metadata: metadata.ELFBinaryPackageNoteJSONPayload,
}
p.SetID()
return p
}
func packageURL(metadata elfBinaryPackageNotes) string {
// TODO: what if the System value is not set?
return packageurl.NewPackageURL(
packageurl.TypeGeneric,
metadata.System,
metadata.Name,
metadata.Version,
nil,
"",
).ToString()
}

View file

@ -0,0 +1,150 @@
package binary
import (
"context"
"debug/elf"
"encoding/json"
"fmt"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/mimetype"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/unionreader"
"github.com/anchore/syft/syft/pkg"
)
var _ pkg.Cataloger = (*elfPackageCataloger)(nil)
type elfPackageCataloger struct {
}
// TODO: for now this accounts for a single data shape from the .note.package section of an ELF binary.
// In the future, this should be generalized to support multiple data shapes, including non-json data.
// For example, fedora includes an ELF section header as a prefix to the JSON payload: https://github.com/anchore/syft/issues/2713
type elfBinaryPackageNotes struct {
Name string `json:"name"`
Version string `json:"version"`
PURL string `json:"purl"`
CPE string `json:"cpe"`
License string `json:"license"`
pkg.ELFBinaryPackageNoteJSONPayload `json:",inline"`
Location file.Location `json:"-"`
}
type elfPackageKey struct {
Name string
Version string
PURL string
CPE string
}
func NewELFPackageCataloger() pkg.Cataloger {
return &elfPackageCataloger{}
}
func (c *elfPackageCataloger) Name() string {
return "elf-binary-package-cataloger"
}
func (c *elfPackageCataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
locations, err := resolver.FilesByMIMEType(mimetype.ExecutableMIMETypeSet.List()...)
if err != nil {
return nil, nil, fmt.Errorf("unable to get binary files by mime type: %w", err)
}
// first find all ELF binaries that have notes
var notesByLocation = make(map[elfPackageKey][]elfBinaryPackageNotes)
for _, location := range locations {
reader, err := resolver.FileContentsByLocation(location)
if err != nil {
return nil, nil, fmt.Errorf("unable to get binary contents %q: %w", location.Path(), err)
}
notes, err := c.parseElfNotes(file.LocationReadCloser{
Location: location,
ReadCloser: reader,
})
if err != nil {
log.WithFields("file", location.Path(), "error", err).Trace("unable to parse ELF notes")
continue
}
if notes == nil {
continue
}
notes.Location = location
key := elfPackageKey{
Name: notes.Name,
Version: notes.Version,
PURL: notes.PURL,
CPE: notes.CPE,
}
notesByLocation[key] = append(notesByLocation[key], *notes)
}
// now we have all ELF binaries that have notes, let's create packages for them.
// we do this in a second pass since it is possible that we have multiple ELF binaries with the same name and version
// which means the set of binaries collectively represent a single logical package.
var pkgs []pkg.Package
for _, notes := range notesByLocation {
noteLocations := file.NewLocationSet()
for _, note := range notes {
noteLocations.Add(note.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
}
// create a package for each unique name/version pair (based on the first note found)
pkgs = append(pkgs, newELFPackage(notes[0], noteLocations, nil))
}
// why not return relationships? We have an executable cataloger that will note the dynamic libraries imported by
// each binary. After all files and packages are processed there is a final task that creates package-to-package
// and package-to-file relationships based on the dynamic libraries imported by each binary.
return pkgs, nil, nil
}
func (c *elfPackageCataloger) parseElfNotes(reader file.LocationReadCloser) (*elfBinaryPackageNotes, error) {
metadata, err := getELFNotes(reader)
if err != nil {
return nil, fmt.Errorf("unable to process ELF binary: %w", err)
}
if metadata == nil || metadata.Name == "" || metadata.Version == "" {
return nil, nil
}
return metadata, nil
}
func getELFNotes(r file.LocationReadCloser) (*elfBinaryPackageNotes, error) {
unionReader, err := unionreader.GetUnionReader(r)
if err != nil {
return nil, fmt.Errorf("unable to get union reader for binary: %w", err)
}
f, err := elf.NewFile(unionReader)
if f == nil || err != nil {
log.WithFields("file", r.Location.Path(), "error", err).Trace("unable to parse binary as ELF")
return nil, nil
}
noteSection := f.Section(".note.package")
if noteSection == nil {
return nil, nil
}
notes, err := noteSection.Data()
if err != nil {
return nil, err
}
var metadata elfBinaryPackageNotes
if err := json.Unmarshal(notes, &metadata); err != nil {
log.WithFields("file", r.Location.Path(), "error", err).Trace("unable to unmarshal ELF package notes as JSON")
return nil, nil
}
return &metadata, err
}

View file

@ -0,0 +1,61 @@
package binary
import (
"testing"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
)
func Test_ELF_Package_Cataloger(t *testing.T) {
expectedPkgs := []pkg.Package{
{
Name: "libhello_world.so",
Version: "0.01",
PURL: "pkg:generic/syftsys/libhello_world.so@0.01",
FoundBy: "",
Locations: file.NewLocationSet(
file.NewVirtualLocation("/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so", "/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib/libhello_world.so"),
file.NewVirtualLocation("/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world.so", "/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world.so"),
file.NewVirtualLocation("/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world2.so", "/usr/local/bin/elftests/elfbinwithsisterlib/lib/libhello_world2.so"),
),
Language: "",
Type: pkg.BinaryPkg,
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "testfixture",
Vendor: "syft",
System: "syftsys",
SourceRepo: "https://github.com/someone/somewhere.git",
Commit: "5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb",
},
},
{
Name: "syfttestfixture",
Version: "0.01",
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
FoundBy: "",
Locations: file.NewLocationSet(
file.NewLocation("/usr/local/bin/elftests/elfbinwithnestedlib/bin/elfbinwithnestedlib").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
file.NewLocation("/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin1").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
file.NewLocation("/usr/local/bin/elftests/elfbinwithsisterlib/bin/elfwithparallellibbin2").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Language: "",
Type: pkg.BinaryPkg,
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "testfixture",
Vendor: "syft",
System: "syftsys",
SourceRepo: "https://github.com/someone/somewhere.git",
Commit: "5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb",
},
},
}
pkgtest.NewCatalogTester().
WithImageResolver(t, "elf-test-fixtures").
IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
Expects(expectedPkgs, nil).
TestCataloger(t, NewELFPackageCataloger())
}

View file

@ -0,0 +1,91 @@
package binary
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)
func Test_packageURL(t *testing.T) {
tests := []struct {
name string
notes elfBinaryPackageNotes
expected string
}{
{
name: "elf-binary-package-cataloger",
notes: elfBinaryPackageNotes{
Name: "github.com/anchore/syft",
Version: "v0.1.0",
ELFBinaryPackageNoteJSONPayload: pkg.ELFBinaryPackageNoteJSONPayload{
System: "syftsys",
},
},
expected: "pkg:generic/syftsys/github.com/anchore/syft@v0.1.0",
},
{
name: "elf binary package short name",
notes: elfBinaryPackageNotes{
Name: "go.opencensus.io",
Version: "v0.23.0",
ELFBinaryPackageNoteJSONPayload: pkg.ELFBinaryPackageNoteJSONPayload{
System: "syftsys",
},
},
expected: "pkg:generic/syftsys/go.opencensus.io@v0.23.0",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, packageURL(test.notes))
})
}
}
func Test_newELFPackage(t *testing.T) {
tests := []struct {
name string
metadata elfBinaryPackageNotes
expected pkg.Package
}{
{
name: "elf-binary-package-cataloger",
metadata: elfBinaryPackageNotes{
Name: "syfttestfixture",
Version: "0.01",
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
CPE: "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01",
ELFBinaryPackageNoteJSONPayload: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "binary",
System: "syftsys",
},
},
expected: pkg.Package{
Name: "syfttestfixture",
Version: "0.01",
Type: "binary",
PURL: "pkg:generic/syftsys/syfttestfixture@0.01",
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "binary",
System: "syftsys",
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := newELFPackage(test.metadata, file.NewLocationSet(), nil)
if diff := cmp.Diff(test.expected, actual, cmpopts.IgnoreFields(pkg.Package{}, "id"), cmpopts.IgnoreUnexported(pkg.Package{}, file.LocationSet{}, pkg.LicenseSet{})); diff != "" {
t.Errorf("newELFPackage() mismatch (-want +got):\n%s", diff)
}
})
}
}

View file

@ -0,0 +1,14 @@
FROM rockylinux:8
RUN dnf update -y; \
dnf install make automake gcc gcc-c++ kernel-devel -y; \
dnf clean all
RUN mkdir -p /usr/local/bin/elftests/elfbinwithnestedlib
RUN mkdir -p /usr/local/bin/elftests/elfbinwithsisterlib
COPY ./elfbinwithnestedlib /usr/local/bin/elftests/elfbinwithnestedlib
COPY ./elfbinwithsisterlib /usr/local/bin/elftests/elfbinwithsisterlib
ENV LD_LIBRARY_PATH=/usr/local/bin/elftests/elfbinwithnestedlib/bin/lib
WORKDIR /usr/local/bin/elftests/elfbinwithnestedlib/
RUN make
WORKDIR /usr/local/bin/elftests/elfbinwithsisterlib
RUN make

View file

@ -0,0 +1,6 @@
#include <iostream>
#include "hello_world.h"
void print_hello_world() {
std::cout << "Hello, World!" << std::endl;
}

View file

@ -0,0 +1,8 @@
#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H
// Function declaration for printing "Hello, World!" to stdout
void print_hello_world();
#endif // HELLO_WORLD_H

View file

@ -0,0 +1,48 @@
LDFLAGS := -L/lib64 -lstdc++
SRC_DIR := ./
BUILD_DIR := ../build
BIN_DIR := ../bin
LIB_DIR := $(BIN_DIR)/lib
LIB_NAME := hello_world
LIB_SRC := $(SRC_DIR)/hello_world.cpp
LIB_OBJ := $(BUILD_DIR)/$(LIB_NAME).o
LIB_SO := $(LIB_DIR)/lib$(LIB_NAME).so
EXECUTABLE := elfbinwithnestedlib
EXEC_SRC := $(SRC_DIR)/testbin.cpp
EXEC_OBJ := $(BUILD_DIR)/$(EXECUTABLE).o
all: testfixture
$(LIB_SO): $(LIB_OBJ) | $(LIB_DIR)
$(CC) -shared -o $@ $<
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "libhello_world.so","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
$(LIB_OBJ): $(LIB_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) -fPIC -c $< -o $@
$(EXEC_OBJ): $(EXEC_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@
$(BIN_DIR):
mkdir -p $(BIN_DIR)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(LIB_DIR):
mkdir -p $(LIB_DIR)
$(BIN_DIR)/$(EXECUTABLE): $(EXEC_OBJ) $(LIB_SO) | $(BIN_DIR)
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_DIR) -l$(LIB_NAME) $(LDFLAGS)
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "syfttestfixture","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
testfixture: $(BIN_DIR)/$(EXECUTABLE)
clean:
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR) $(EXECUTABLE)
.PHONY: all clean

View file

@ -0,0 +1,8 @@
#include "hello_world.h"
int main() {
// Call the function from the shared library
print_hello_world();
return 0;
}

View file

@ -0,0 +1,18 @@
CC = g++
CFLAGS = -std=c++17 -Wall -Wextra -pedantic
BUILD_DIR := ./build
BIN_DIR := ./bin
LIB_DIR := $(BIN_DIR)/lib
all: testfixtures
testfixtures:
$(MAKE) -C elfsrc
clean:
rm -rf $(BUILD_DIR) $(BIN_DIR)
.PHONY: all clean testfixtures

View file

@ -0,0 +1,6 @@
#include <iostream>
#include "hello_world.h"
void print_hello_world() {
std::cout << "Hello, World!" << std::endl;
}

View file

@ -0,0 +1,8 @@
#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H
// Function declaration for printing "Hello, World!" to stdout
void print_hello_world();
#endif // HELLO_WORLD_H

View file

@ -0,0 +1,48 @@
LDFLAGS := -L/lib64 -lstdc++
SRC_DIR := ./
BUILD_DIR := ../build
LIB_DIR := ../lib
BIN_DIR := ../bin
LIB_NAME := hello_world
LIB_SRC := $(SRC_DIR)/hello_world.cpp
LIB_OBJ := $(BUILD_DIR)/$(LIB_NAME).o
LIB_SO := $(LIB_DIR)/lib$(LIB_NAME).so
EXECUTABLE := elfwithparallellibbin1
EXEC_SRC := $(SRC_DIR)/testbin.cpp
EXEC_OBJ := $(BUILD_DIR)/$(EXECUTABLE).o
all: testfixture
$(LIB_SO): $(LIB_OBJ) | $(LIB_DIR)
$(CC) -shared -o $@ $<
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "libhello_world.so","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
$(LIB_OBJ): $(LIB_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) -fPIC -c $< -o $@
$(EXEC_OBJ): $(EXEC_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@
$(BIN_DIR):
mkdir -p $(BIN_DIR)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(LIB_DIR):
mkdir -p $(LIB_DIR)
$(BIN_DIR)/$(EXECUTABLE): $(EXEC_OBJ) $(LIB_SO) | $(BIN_DIR)
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_DIR) -l$(LIB_NAME) $(LDFLAGS)
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "syfttestfixture","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
testfixture: $(BIN_DIR)/$(EXECUTABLE)
clean:
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR) $(EXECUTABLE)
.PHONY: all clean

View file

@ -0,0 +1,8 @@
#include "hello_world.h"
int main() {
// Call the function from the shared library
print_hello_world();
return 0;
}

View file

@ -0,0 +1,6 @@
#include <iostream>
#include "hello_world2.h"
void print_hello_world() {
std::cout << "Hello, World again!!" << std::endl;
}

View file

@ -0,0 +1,8 @@
#ifndef HELLO_WORLD2_H
#define HELLO_WORLD2_H
// Function declaration for printing "Hello, World!" to stdout
void print_hello_world();
#endif // HELLO_WORLD2_H

View file

@ -0,0 +1,48 @@
LDFLAGS := -L/lib64 -lstdc++
SRC_DIR := ./
BUILD_DIR := ../build
LIB_DIR := ../lib
BIN_DIR := ../bin
LIB_NAME := hello_world2
LIB_SRC := $(SRC_DIR)/hello_world2.cpp
LIB_OBJ := $(BUILD_DIR)/$(LIB_NAME).o
LIB_SO := $(LIB_DIR)/lib$(LIB_NAME).so
EXECUTABLE := elfwithparallellibbin2
EXEC_SRC := $(SRC_DIR)/testbin2.cpp
EXEC_OBJ := $(BUILD_DIR)/$(EXECUTABLE).o
all: testfixture
$(LIB_SO): $(LIB_OBJ) | $(LIB_DIR)
$(CC) -shared -o $@ $<
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "libhello_world.so","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
$(LIB_OBJ): $(LIB_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) -fPIC -c $< -o $@
$(EXEC_OBJ): $(EXEC_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@
$(BIN_DIR):
mkdir -p $(BIN_DIR)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(LIB_DIR):
mkdir -p $(LIB_DIR)
$(BIN_DIR)/$(EXECUTABLE): $(EXEC_OBJ) $(LIB_SO) | $(BIN_DIR)
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_DIR) -l$(LIB_NAME) $(LDFLAGS)
echo '{"type": "testfixture","license":"MIT","commit":"5534c38d0ffef9a3f83154f0b7a7fb6ab0ab6dbb","sourceRepo":"https://github.com/someone/somewhere.git","vendor": "syft","system": "syftsys","name": "syfttestfixture","version": "0.01","purl": "pkg:generic/syftsys/syfttestfixture@0.01","cpe": "cpe:/o:syft:syftsys_testfixture_syfttestfixture:0.01"}' | objcopy --add-section .note.package=/dev/stdin --set-section-flags .note.package=noload,readonly $@
testfixture: $(BIN_DIR)/$(EXECUTABLE)
clean:
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR) $(EXECUTABLE)
.PHONY: all clean

View file

@ -0,0 +1,8 @@
#include "hello_world2.h"
int main() {
// Call the function from the shared library
print_hello_world();
return 0;
}

View file

@ -0,0 +1,18 @@
CC = g++
CFLAGS = -std=c++17 -Wall -Wextra -pedantic
BUILD_DIR := ./build
LIB_DIR := ./lib
BIN_DIR := ./bin
all: testfixtures
testfixtures:
$(MAKE) -C elfsrc1
$(MAKE) -C elfsrc2
clean:
rm -rf $(BUILD_DIR) $(LIB_DIR) $(BIN_DIR)
.PHONY: all clean testfixtures