Skip to content

Commit

Permalink
Initial Go Language support (#350)
Browse files Browse the repository at this point in the history
* Introduced Go parsing using JNI
  • Loading branch information
oxisto authored Mar 18, 2021
1 parent 28dddb7 commit 699776f
Show file tree
Hide file tree
Showing 40 changed files with 2,690 additions and 36 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
fi
echo "##[set-output name=version;]$VERSION"
id: determine_version
- name: Build cpgo
run: |
cd go-jni && ./build.sh && sudo cp ../libcpgo.so /usr/lib/
- name: Build ${{ steps.determine_version.outputs.version }}
run: |
if [ "$SONAR_TOKEN" != "" ]
Expand All @@ -43,6 +46,12 @@ jobs:
VERSION: ${{ steps.determine_version.outputs.version }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Archive test reports
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: test
path: build/reports/tests/test
- name: JavaDoc
if: startsWith(github.ref, 'refs/tags/v')
uses: JamesIves/github-pages-deploy-action@releases/v3
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ logs
/lsp/*.log
*.class

*.dylib
*.so
*.h
*.log

10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![Actions Status](https://github.com/Fraunhofer-AISEC/cpg/workflows/build/badge.svg)](https://github.com/Fraunhofer-AISEC/cpg/actions)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Fraunhofer-AISEC_cpg&metric=alert_status)](https://sonarcloud.io/dashboard?id=Fraunhofer-AISEC_cpg) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Fraunhofer-AISEC_cpg&metric=security_rating)](https://sonarcloud.io/dashboard?id=Fraunhofer-AISEC_cpg) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Fraunhofer-AISEC_cpg&metric=coverage)](https://sonarcloud.io/dashboard?id=Fraunhofer-AISEC_cpg)

A simple library to extract a *code property graph* out of source code. It has support for multiple passes that can extend the analysis after the graph is constructed. It currently supports C/C++ (C17) and Java (Java 13).
A simple library to extract a *code property graph* out of source code. It has support for multiple passes that can extend the analysis after the graph is constructed. It currently supports C/C++ (C17), Java (Java 13) and has experimental support for Golang.

## What is this?

Expand Down Expand Up @@ -73,6 +73,14 @@ func.getSignature();
func.getParameters();
```

### Usage of Experimental Languages

Some languages, such as Golang are marked as experimental and depend on other native libraries. These are NOT YET bundled in the release jars, so you need to build them manually.

#### Golang

In the case of Golang, the necessary native code can be found in the `go-jni` folder. In order to build it you can use the `build.sh` script, which uses `java_home` to automatically find JNI headers and stores the finished library in the cpg root folder. This currently only works for Linux and macOS.

## Development Setup

### Code Style
Expand Down
17 changes: 17 additions & 0 deletions go-jni/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "go: build",
"type": "shell",
"problemMatcher": [],
"command": "./build.sh",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
39 changes: 39 additions & 0 deletions go-jni/basic_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cpg

import (
"log"

"tekao.net/jnigi"
)

func NewString(s string) *jnigi.ObjectRef {
o, err := env.NewObject("java/lang/String", []byte(s))
if err != nil {
log.Fatal(err)

}

return o
}

func NewInteger(i int) *jnigi.ObjectRef {
// TODO: Use Integer.valueOf
o, err := env.NewObject("java/lang/Integer", i)
if err != nil {
log.Fatal(err)

}

return o
}

func NewDouble(d float64) *jnigi.ObjectRef {
// TODO: Use Integer.valueOf
o, err := env.NewObject("java/lang/Double", d)
if err != nil {
log.Fatal(err)

}

return o
}
18 changes: 18 additions & 0 deletions go-jni/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
ARCH=`uname -s | tr '[:upper:]' '[:lower:]'`

if [ $ARCH == "darwin" ]
then
EXTENSION="dylib"
else
EXTENSION="so"
fi

if [ "$JAVA_HOME" == "" ]
then
JAVA_HOME=`/usr/libexec/java_home`
fi

export CGO_CFLAGS="-I${JAVA_HOME}/include -I/${JAVA_HOME}/include/${ARCH}"

go build -buildmode=c-shared -o ../libcpgo.${EXTENSION} lib/cpg/main.go
256 changes: 256 additions & 0 deletions go-jni/declarations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
package cpg

import (
"go/ast"
"go/token"
"log"
"runtime/debug"

"tekao.net/jnigi"
)

type Declaration jnigi.ObjectRef
type IncludeDeclaration jnigi.ObjectRef
type TranslationUnitDeclaration Declaration
type FunctionDeclaration Declaration
type MethodDeclaration FunctionDeclaration
type RecordDeclaration Declaration
type FieldDeclaration Declaration
type VariableDeclaration Declaration
type ParamVariableDeclaration Declaration
type NamespaceDeclaration Declaration

func (n *NamespaceDeclaration) SetName(s string) error {
return (*Node)(n).SetName(s)
}

func (n *IncludeDeclaration) SetName(s string) error {
return (*Node)(n).SetName(s)
}

func (n *IncludeDeclaration) SetFilename(s string) error {
return (*jnigi.ObjectRef)(n).SetField(env, "filename", NewString(s))
}

func (f *FunctionDeclaration) SetName(s string) error {
return (*Node)(f).SetName(s)
}

func (f *FunctionDeclaration) SetType(t *Type) {
(*HasType)(f).SetType(t)
}

func (f *FunctionDeclaration) AddParameter(p *ParamVariableDeclaration) {
(*jnigi.ObjectRef)(f).CallMethod(env, "addParameter", jnigi.Void, (*jnigi.ObjectRef)(p))
}

func (f *FunctionDeclaration) SetBody(s *Statement) (err error) {
_, err = (*jnigi.ObjectRef)(f).CallMethod(env, "setBody", jnigi.Void, (*jnigi.ObjectRef)(s).Cast("de/fraunhofer/aisec/cpg/graph/statements/Statement"))

return
}

func (m *MethodDeclaration) SetName(s string) error {
return (*Node)(m).SetName(s)
}

func (m *MethodDeclaration) SetType(t *Type) {
(*HasType)(m).SetType(t)
}

func (m *MethodDeclaration) SetReceiver(v *VariableDeclaration) error {
return (*jnigi.ObjectRef)(m).SetField(env, "receiver", (*jnigi.ObjectRef)(v))
}

func (m *MethodDeclaration) GetReceiver() *VariableDeclaration {
o, err := (*jnigi.ObjectRef)(m).GetField(env, "receiver", jnigi.ObjectType("de/fraunhofer/aisec/cpg/graph/declarations/VariableDeclaration"))

if err != nil {
log.Fatal(err)
debug.PrintStack()
}

return (*VariableDeclaration)(o.(*jnigi.ObjectRef))
}

func (p *ParamVariableDeclaration) SetType(t *Type) {
(*HasType)(p).SetType(t)
}

func (p *ParamVariableDeclaration) SetName(s string) error {
return (*Node)(p).SetName(s)
}

func (f *FieldDeclaration) SetName(s string) error {
return (*Node)(f).SetName(s)
}

func (f *FieldDeclaration) SetType(t *Type) {
(*HasType)(f).SetType(t)
}

func (v *VariableDeclaration) SetType(t *Type) {
(*HasType)(v).SetType(t)
}

func (v *VariableDeclaration) SetName(s string) error {
return (*Node)(v).SetName(s)
}

func (v *VariableDeclaration) IsNil() bool {
return (*jnigi.ObjectRef)(v).IsNil()
}

func (v *VariableDeclaration) SetInitializer(e *Expression) (err error) {
_, err = (*jnigi.ObjectRef)(v).CallMethod(env, "setInitializer", jnigi.Void, (*jnigi.ObjectRef)(e).Cast("de/fraunhofer/aisec/cpg/graph/statements/expressions/Expression"))

return
}

func (v *VariableDeclaration) Declaration() *Declaration {
return (*Declaration)(v)
}

func (t *TranslationUnitDeclaration) GetIncludeByName(s string) *IncludeDeclaration {
i, err := (*jnigi.ObjectRef)(t).CallMethod(env, "getIncludeByName", jnigi.ObjectType("de/fraunhofer/aisec/cpg/graph/declarations/IncludeDeclaration"), NewString(s))
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

return (*IncludeDeclaration)(i.(*jnigi.ObjectRef))
}

func (r *RecordDeclaration) SetName(s string) error {
return (*Node)(r).SetName(s)
}

func (r *RecordDeclaration) SetKind(s string) error {
return (*jnigi.ObjectRef)(r).SetField(env, "kind", NewString(s))
}

func (r *RecordDeclaration) AddMethod(m *MethodDeclaration) (err error) {
_, err = (*jnigi.ObjectRef)(r).CallMethod(env, "addMethod", jnigi.Void, (*jnigi.ObjectRef)(m))

return
}

func (r *RecordDeclaration) IsNil() bool {
return (*jnigi.ObjectRef)(r).IsNil()
}

func (r *MethodDeclaration) IsNil() bool {
return (*jnigi.ObjectRef)(r).IsNil()
}

func (r *CompoundStatement) IsNil() bool {
return (*jnigi.ObjectRef)(r).IsNil()
}

func (c *CaseStatement) SetCaseExpression(e *Expression) error {
return (*jnigi.ObjectRef)(c).SetField(env, "caseExpression", (*jnigi.ObjectRef)(e).Cast("de/fraunhofer/aisec/cpg/graph/statements/expressions/Expression"))
}

func NewTranslationUnitDeclaration(fset *token.FileSet, astNode ast.Node, name string, code string) *TranslationUnitDeclaration {
o, err := env.CallStaticMethod("de/fraunhofer/aisec/cpg/graph/NodeBuilder", "newTranslationUnitDeclaration", jnigi.ObjectType("de/fraunhofer/aisec/cpg/graph/declarations/TranslationUnitDeclaration"), NewString(name), NewString(code))
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

return (*TranslationUnitDeclaration)(o.(*jnigi.ObjectRef))
}

func NewNamespaceDeclaration(fset *token.FileSet, astNode ast.Node, name string, code string) *NamespaceDeclaration {
o, err := env.CallStaticMethod("de/fraunhofer/aisec/cpg/graph/NodeBuilder", "newNamespaceDeclaration", jnigi.ObjectType("de/fraunhofer/aisec/cpg/graph/declarations/NamespaceDeclaration"), NewString(name), NewString(code))
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

return (*NamespaceDeclaration)(o.(*jnigi.ObjectRef))
}

func NewIncludeDeclaration(fset *token.FileSet, astNode ast.Node) *IncludeDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/IncludeDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*IncludeDeclaration)(tu)
}

func NewFunctionDeclaration(fset *token.FileSet, astNode ast.Node) *FunctionDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/FunctionDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*FunctionDeclaration)(tu)
}

func NewMethodDeclaration(fset *token.FileSet, astNode ast.Node) *MethodDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*MethodDeclaration)(tu)
}

func NewRecordDeclaration(fset *token.FileSet, astNode ast.Node) *RecordDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/RecordDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*RecordDeclaration)(tu)
}

func NewVariableDeclaration(fset *token.FileSet, astNode ast.Node) *VariableDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/VariableDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*VariableDeclaration)(tu)
}

func NewParamVariableDeclaration(fset *token.FileSet, astNode ast.Node) *ParamVariableDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/ParamVariableDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*ParamVariableDeclaration)(tu)
}

func NewFieldDeclaration(fset *token.FileSet, astNode ast.Node) *FieldDeclaration {
tu, err := env.NewObject("de/fraunhofer/aisec/cpg/graph/declarations/FieldDeclaration")
if err != nil {
log.Fatal(err)
debug.PrintStack()
}

updateCode(fset, (*Node)(tu), astNode)

return (*FieldDeclaration)(tu)
}
Loading

0 comments on commit 699776f

Please sign in to comment.