This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-rover.git


The following commit(s) were added to refs/heads/main by this push:
     new 7c5e314  Support analyze the data from GoTLS (#46)
7c5e314 is described below

commit 7c5e3141444730bb2896a90639012c98d912624a
Author: mrproliu <[email protected]>
AuthorDate: Fri Aug 12 08:07:57 2022 +0800

    Support analyze the data from GoTLS (#46)
---
 CHANGES.md                               |   2 +-
 bpf/profiling/network/args.h             |   2 +
 bpf/profiling/network/go_tls.c           | 223 +++++++++++++++++++++++
 bpf/profiling/network/go_tls.h           | 150 ++++++++++++++++
 bpf/profiling/network/netmonitor.c       |  37 ++--
 docs/en/setup/configuration/profiling.md |   2 +-
 go.mod                                   |   1 +
 go.sum                                   |   3 +
 pkg/profiling/task/network/enums.go      |   7 +
 pkg/profiling/task/network/linker.go     | 139 ++++++++++++---
 pkg/profiling/task/network/ssl.go        | 252 +++++++++++++++++++++++++-
 pkg/tools/elf/abi.go                     | 146 +++++++++++++++
 pkg/tools/elf/dwarf.go                   |  83 +++++++++
 pkg/tools/elf/dwarf_init.go              | 293 +++++++++++++++++++++++++++++++
 pkg/tools/elf/elf.go                     | 107 +++++++++++
 pkg/tools/elf/enums.go                   |  87 +++++++++
 pkg/tools/elf/function.go                |  39 ++++
 pkg/tools/elf/structure.go               |  37 ++++
 pkg/tools/profiling/api.go               |   1 +
 pkg/tools/profiling/go_library.go        |   2 +-
 pkg/tools/profiling/kernel.go            |   1 +
 21 files changed, 1566 insertions(+), 48 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 5213e78..fab4e08 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,7 +7,7 @@ Release Notes.
 #### Features
 * Support `NETWORK` Profiling.
 * Let the logger as a configurable module.
-* Support analyze the data of OpenSSL, BoringSSL library in `NETWORK` 
Profiling.
+* Support analyze the data of OpenSSL, BoringSSL library, GoTLS in `NETWORK` 
Profiling.
 
 #### Bug Fixes
 * Fixed reading process paths incorrect when running as a container.
diff --git a/bpf/profiling/network/args.h b/bpf/profiling/network/args.h
index b9bcc59..8247514 100644
--- a/bpf/profiling/network/args.h
+++ b/bpf/profiling/network/args.h
@@ -44,6 +44,8 @@
 #define SOCKET_OPTS_TYPE_RESENT     17
 #define SOCKET_OPTS_TYPE_SSL_WRITE  18
 #define SOCKET_OPTS_TYPE_SSL_READ   19
+#define SOCKET_OPTS_TYPE_GOTLS_WRITE 20
+#define SOCKET_OPTS_TYPE_GOTLS_READ  21
 
 // tracepoint enter
 struct trace_event_raw_sys_enter {
diff --git a/bpf/profiling/network/go_tls.c b/bpf/profiling/network/go_tls.c
new file mode 100644
index 0000000..6422ad2
--- /dev/null
+++ b/bpf/profiling/network/go_tls.c
@@ -0,0 +1,223 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+#include "go_tls.h"
+
+SEC("uprobe/casgstatus")
+int go_casgstatus(struct pt_regs* ctx) {
+    const void* sp = (const void*)PT_REGS_SP(ctx);
+    uint64_t* regs = go_regabi_regs(ctx);
+    if (regs == NULL) {
+       return 0;
+    }
+
+    __u64 id = bpf_get_current_pid_tgid();
+    __u32 tgid = id >> 32;
+    struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+    if (symaddrs == NULL) {
+       return 0;
+    }
+
+    // get runtime.g
+    void* gptr = NULL;
+    assign_go_tls_arg(&gptr, sizeof(gptr), symaddrs->casg_status_gp_loc, sp, 
regs);
+    if (gptr == NULL) {
+        return 0;
+    }
+
+    // get goid in runtime.g
+    int64_t goid;
+    bpf_probe_read(&goid, sizeof(goid), gptr + symaddrs->gid_offset);
+
+    // newval in runtime.g
+    __u32 status;
+    assign_go_tls_arg(&status, sizeof(status), 
symaddrs->casg_status_new_val_loc, sp, regs);
+
+    const int runningStatus = 2;
+    if (status == runningStatus) {
+        set_goid(id, goid);
+    }
+    return 0;
+}
+
+SEC("uprobe/go_tls_write")
+int go_tls_write(struct pt_regs* ctx) {
+    __u64 id = bpf_get_current_pid_tgid();
+    __u32 tgid = id >> 32;
+
+    __u64 goid = get_goid(id);
+    if (goid == 0) {
+        return 0;
+    }
+
+    struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+    if (symaddrs == NULL) {
+        return 0;
+    }
+
+    const void* sp = (const void*)PT_REGS_SP(ctx);
+    uint64_t* regs = go_regabi_regs(ctx);
+    if (regs == NULL) {
+        return 0;
+    }
+
+    struct go_tls_tgid_goid_t tgid_goid = {};
+    tgid_goid.tgid = tgid;
+    tgid_goid.goid = goid;
+
+    struct go_tls_connection_args_t data_args = {};
+    assign_go_tls_arg(&data_args.connection_ptr, 
sizeof(data_args.connection_ptr), symaddrs->write_connection_loc, sp, regs);
+    assign_go_tls_arg(&data_args.buffer_ptr, sizeof(data_args.buffer_ptr), 
symaddrs->write_buffer_loc, sp, regs);
+    bpf_map_update_elem(&go_tls_active_connection_args, &tgid_goid, 
&data_args, 0);
+    return 0;
+}
+
+SEC("uretprobe/go_tls_write")
+int go_tls_write_ret(struct pt_regs* ctx) {
+    __u64 id = bpf_get_current_pid_tgid();
+    __u32 tgid = id >> 32;
+
+    __u64 goid = get_goid(id);
+    if (goid == 0) {
+        return 0;
+    }
+
+    struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+    if (symaddrs == NULL) {
+        return 0;
+    }
+
+    const void* sp = (const void*)PT_REGS_SP(ctx);
+    uint64_t* regs = go_regabi_regs(ctx);
+    if (regs == NULL) {
+        return 0;
+    }
+
+    int64_t retval0 = 0;
+    assign_go_tls_arg(&retval0, sizeof(retval0), symaddrs->write_ret0_loc, sp, 
regs);
+    struct go_interface retval1 = {};
+    assign_go_tls_arg(&retval1, sizeof(retval1), symaddrs->write_ret1_loc, sp, 
regs);
+    if (retval1.ptr != 0) {
+        return 0;
+    }
+
+    struct go_tls_tgid_goid_t tgid_goid = {};
+    tgid_goid.tgid = tgid;
+    tgid_goid.goid = goid;
+
+    struct go_tls_connection_args_t *args = 
bpf_map_lookup_elem(&go_tls_active_connection_args, &tgid_goid);
+    if (args) {
+        struct go_interface conn_intf = {};
+        conn_intf.type = 1;
+        conn_intf.ptr = args->connection_ptr;
+        int fd = get_fd_from_go_tls_conn(conn_intf, symaddrs);
+
+        set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_GOTLS_WRITE);
+
+        struct sock_data_args_t data_args = {};
+        data_args.fd = fd;
+        data_args.buf = args->buffer_ptr;
+
+        process_write_data(ctx, id, &data_args, retval0, 
SOCK_DATA_DIRECTION_EGRESS, false, SOCKET_OPTS_TYPE_GOTLS_WRITE, true);
+    }
+    bpf_map_delete_elem(&go_tls_active_connection_args, &tgid_goid);
+    return 0;
+}
+
+SEC("uprobe/go_tls_read")
+int go_tls_read(struct pt_regs* ctx) {
+    __u64 id = bpf_get_current_pid_tgid();
+    __u32 tgid = id >> 32;
+
+    __u64 goid = get_goid(id);
+    if (goid == 0) {
+        return 0;
+    }
+
+    struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+    if (symaddrs == NULL) {
+        return 0;
+    }
+
+    const void* sp = (const void*)PT_REGS_SP(ctx);
+    uint64_t* regs = go_regabi_regs(ctx);
+    if (regs == NULL) {
+        return 0;
+    }
+
+    struct go_tls_tgid_goid_t tgid_goid = {};
+    tgid_goid.tgid = tgid;
+    tgid_goid.goid = goid;
+
+    struct go_tls_connection_args_t data_args = {};
+    assign_go_tls_arg(&data_args.connection_ptr, 
sizeof(data_args.connection_ptr), symaddrs->read_connection_loc, sp, regs);
+    assign_go_tls_arg(&data_args.buffer_ptr, sizeof(data_args.buffer_ptr), 
symaddrs->read_buffer_loc, sp, regs);
+    bpf_map_update_elem(&go_tls_active_connection_args, &tgid_goid, 
&data_args, 0);
+    return 0;
+}
+
+SEC("uretprobe/go_tls_read")
+int go_tls_read_ret(struct pt_regs* ctx) {
+    __u64 id = bpf_get_current_pid_tgid();
+    __u32 tgid = id >> 32;
+
+    __u64 goid = get_goid(id);
+    if (goid == 0) {
+        return 0;
+    }
+
+    struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+    if (symaddrs == NULL) {
+        return 0;
+    }
+
+    const void* sp = (const void*)PT_REGS_SP(ctx);
+    uint64_t* regs = go_regabi_regs(ctx);
+    if (regs == NULL) {
+        return 0;
+    }
+
+    int64_t retval0 = 0;
+    assign_go_tls_arg(&retval0, sizeof(retval0), symaddrs->read_ret0_loc, sp, 
regs);
+    struct go_interface retval1 = {};
+    assign_go_tls_arg(&retval1, sizeof(retval1), symaddrs->read_ret1_loc, sp, 
regs);
+    if (retval1.ptr != 0) {
+        return 0;
+    }
+
+    struct go_tls_tgid_goid_t tgid_goid = {};
+    tgid_goid.tgid = tgid;
+    tgid_goid.goid = goid;
+
+    struct go_tls_connection_args_t *args = 
bpf_map_lookup_elem(&go_tls_active_connection_args, &tgid_goid);
+    if (args) {
+        struct go_interface conn_intf = {};
+        conn_intf.type = 1;
+        conn_intf.ptr = args->connection_ptr;
+        int fd = get_fd_from_go_tls_conn(conn_intf, symaddrs);
+
+        set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_GOTLS_READ);
+
+        struct sock_data_args_t data_args = {};
+        data_args.fd = fd;
+        data_args.buf = args->buffer_ptr;
+
+        process_write_data(ctx, id, &data_args, retval0, 
SOCK_DATA_DIRECTION_INGRESS, false, SOCKET_OPTS_TYPE_GOTLS_WRITE, true);
+    }
+    bpf_map_delete_elem(&go_tls_active_connection_args, &tgid_goid);
+    return 0;
+}
\ No newline at end of file
diff --git a/bpf/profiling/network/go_tls.h b/bpf/profiling/network/go_tls.h
new file mode 100644
index 0000000..7b800eb
--- /dev/null
+++ b/bpf/profiling/network/go_tls.h
@@ -0,0 +1,150 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+struct go_tls_arg_location_t {
+    __u32 type;
+    __u32 offset;
+};
+
+struct go_tls_args_symaddr_t {
+    __u64 fd_sys_offset;
+    __u64 tls_conn_offset;
+    __u64 gid_offset;
+    __u64 tcp_conn_offset;
+
+    // casg
+    struct go_tls_arg_location_t casg_status_gp_loc;
+    struct go_tls_arg_location_t casg_status_new_val_loc;
+
+    // read
+    struct go_tls_arg_location_t read_connection_loc;
+    struct go_tls_arg_location_t read_buffer_loc;
+    struct go_tls_arg_location_t read_ret0_loc;
+    struct go_tls_arg_location_t read_ret1_loc;
+
+    // write
+    struct go_tls_arg_location_t write_connection_loc;
+    struct go_tls_arg_location_t write_buffer_loc;
+    struct go_tls_arg_location_t write_ret0_loc;
+    struct go_tls_arg_location_t write_ret1_loc;
+};
+
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(max_entries, 10000);
+       __type(key, __u32);
+       __type(value, struct go_tls_args_symaddr_t);
+} go_tls_args_symaddr_map SEC(".maps");
+static __inline struct go_tls_args_symaddr_t* get_go_tls_args_symaddr(__u32 
tgid) {
+    struct go_tls_args_symaddr_t *addr = 
bpf_map_lookup_elem(&go_tls_args_symaddr_map, &tgid);
+    return addr;
+}
+
+struct go_tls_tgid_goid_t {
+    __u64 tgid;
+    __u64 goid;
+};
+struct go_tls_connection_args_t {
+    void* connection_ptr;
+    char* buffer_ptr;
+};
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(max_entries, 10000);
+       __type(key, struct go_tls_tgid_goid_t);
+       __type(value, struct go_tls_connection_args_t);
+} go_tls_active_connection_args SEC(".maps");
+
+
+struct go_regabi_regs_t {
+    __u64 regs[9];
+};
+struct {
+    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+    __type(key, __u32);
+    __type(value, struct go_regabi_regs_t);
+    __uint(max_entries, 1);
+} go_regabi_regs_map SEC(".maps");
+// Copies the registers of the golang ABI, so that they can be
+// easily accessed using an offset.
+static __inline uint64_t* go_regabi_regs(const struct pt_regs* ctx) {
+    __u32 zero = 0;
+    struct go_regabi_regs_t* regs_heap_var = 
bpf_map_lookup_elem(&go_regabi_regs_map, &zero);
+    if (regs_heap_var == NULL) {
+        return NULL;
+    }
+
+    regs_heap_var->regs[0] = ctx->rax;
+    regs_heap_var->regs[1] = ctx->rbx;
+    regs_heap_var->regs[2] = ctx->rcx;
+    regs_heap_var->regs[3] = ctx->rdi;
+    regs_heap_var->regs[4] = ctx->rsi;
+    regs_heap_var->regs[5] = ctx->r8;
+    regs_heap_var->regs[6] = ctx->r9;
+    regs_heap_var->regs[7] = ctx->r10;
+    regs_heap_var->regs[8] = ctx->r11;
+
+    return regs_heap_var->regs;
+}
+
+struct go_interface {
+    int64_t type;
+    void* ptr;
+};
+
+static __inline void assign_go_tls_arg(void* arg, size_t arg_size, struct 
go_tls_arg_location_t loc, const void* sp,
+                                uint64_t* regs) {
+    // stack type
+    if (loc.type == 1) {
+        bpf_probe_read(arg, arg_size, sp + loc.offset);
+    } else if (loc.type == 2) {
+        // register type
+        if (loc.offset >= 0 && loc.offset <= 30) {
+            bpf_probe_read(arg, arg_size, (char*)regs + loc.offset);
+        }
+    }
+}
+
+static __inline int get_fd_from_go_tls_conn(struct go_interface conn, struct 
go_tls_args_symaddr_t* symaddr) {
+    // read connection
+    bpf_probe_read(&conn, sizeof(conn), conn.ptr + symaddr->tls_conn_offset);
+
+    if (conn.type != symaddr->tcp_conn_offset) {
+        return 0;
+    }
+
+    void* fd_ptr;
+    bpf_probe_read(&fd_ptr, sizeof(fd_ptr), conn.ptr);
+    __u64 sysfd;
+    bpf_probe_read(&sysfd, sizeof(sysfd), fd_ptr + symaddr->fd_sys_offset);
+    return sysfd;
+}
+
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(max_entries, 1024);
+       __type(key, __u64);
+       __type(value, __u64);
+} go_tgid_goid_map SEC(".maps");
+static __inline __u64 get_goid(__u64 tgid) {
+    __u64 *val;
+    val = bpf_map_lookup_elem(&go_tgid_goid_map, &tgid);
+    return !val ? 0 : *val;
+}
+static __inline void set_goid(__u64 tgid, __u64 goid) {
+    bpf_map_update_elem(&go_tgid_goid_map, &tgid, &goid, 0);
+}
\ No newline at end of file
diff --git a/bpf/profiling/network/netmonitor.c 
b/bpf/profiling/network/netmonitor.c
index c929b22..233a51b 100644
--- a/bpf/profiling/network/netmonitor.c
+++ b/bpf/profiling/network/netmonitor.c
@@ -359,22 +359,24 @@ static __always_inline void process_write_data(struct 
pt_regs *ctx, __u64 id, st
         }
     }
 
-    // add statics
-    __u64 exe_time = curr_nacs - args->start_nacs;
-    if (data_direction == SOCK_DATA_DIRECTION_EGRESS) {
-        conn->write_bytes += bytes_count;
-        conn->write_count++;
-        conn->write_exe_time += exe_time;
-
-        add_to_socket_connection_stats_histogram(conid, conn->random_id, 
SOCK_DATA_DIRECTION_EGRESS,
-                        SOCKET_CONNECTION_STATS_HISTOGRAM_DATA_TYPE_EXE_TIME, 
exe_time);
-    } else {
-        conn->read_bytes += bytes_count;
-        conn->read_count++;
-        conn->read_exe_time += exe_time;
-
-        add_to_socket_connection_stats_histogram(conid, conn->random_id, 
SOCK_DATA_DIRECTION_INGRESS,
-                                
SOCKET_CONNECTION_STATS_HISTOGRAM_DATA_TYPE_EXE_TIME, exe_time);
+    // add statics when is not ssl(native buffer)
+    if (ssl == false) {
+        __u64 exe_time = curr_nacs - args->start_nacs;
+        if (data_direction == SOCK_DATA_DIRECTION_EGRESS) {
+            conn->write_bytes += bytes_count;
+            conn->write_count++;
+            conn->write_exe_time += exe_time;
+
+            add_to_socket_connection_stats_histogram(conid, conn->random_id, 
SOCK_DATA_DIRECTION_EGRESS,
+                            
SOCKET_CONNECTION_STATS_HISTOGRAM_DATA_TYPE_EXE_TIME, exe_time);
+        } else {
+            conn->read_bytes += bytes_count;
+            conn->read_count++;
+            conn->read_exe_time += exe_time;
+
+            add_to_socket_connection_stats_histogram(conid, conn->random_id, 
SOCK_DATA_DIRECTION_INGRESS,
+                                    
SOCKET_CONNECTION_STATS_HISTOGRAM_DATA_TYPE_EXE_TIME, exe_time);
+        }
     }
 
     // RTT
@@ -1127,4 +1129,5 @@ int tcp_drop(struct pt_regs *ctx) {
     return 0;
 }
 
-#include "openssl.c"
\ No newline at end of file
+#include "openssl.c"
+#include "go_tls.c"
\ No newline at end of file
diff --git a/docs/en/setup/configuration/profiling.md 
b/docs/en/setup/configuration/profiling.md
index 0e3ba42..94d9674 100644
--- a/docs/en/setup/configuration/profiling.md
+++ b/docs/en/setup/configuration/profiling.md
@@ -30,7 +30,7 @@ Off CPU Profiling task is attach the `finish_task_switch` in 
`krobe` to profilin
 ### Network
 
 Network Profiling task is intercept IO-related syscall and `urprobe` in 
process to identify the network traffic and generate the metrics.
-Also, the following protocol are supported for analyzing using OpenSSL 
library, BoringSSL library or plaintext:
+Also, the following protocol are supported for analyzing using OpenSSL 
library, BoringSSL library, GoTLS or plaintext:
 
 1. HTTP
 2. MySQL
diff --git a/go.mod b/go.mod
index 5c74485..6e4a631 100644
--- a/go.mod
+++ b/go.mod
@@ -13,6 +13,7 @@ require (
        github.com/sirupsen/logrus v1.8.1
        github.com/spf13/cobra v1.3.0
        github.com/spf13/viper v1.10.1
+       golang.org/x/arch v0.0.0-20220722155209-00200b7164a7
        golang.org/x/sys v0.0.0-20211210111614-af8b64212486
        google.golang.org/grpc v1.44.0
        k8s.io/api v0.23.5
diff --git a/go.sum b/go.sum
index 0d475d3..d2876d2 100644
--- a/go.sum
+++ b/go.sum
@@ -452,6 +452,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod 
h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
 go.uber.org/atomic v1.7.0/go.mod 
h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/multierr v1.6.0/go.mod 
h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+golang.org/x/arch v0.0.0-20220722155209-00200b7164a7 
h1:VBQqJMNMRfQsWSiCTLgz9XjAfWlgnJAPv8nsp1HF8Tw=
+golang.org/x/arch v0.0.0-20220722155209-00200b7164a7/go.mod 
h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -933,6 +935,7 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod 
h1:jPW/WVKK9YHAvNhRxK0md/
 k8s.io/utils v0.0.0-20211116205334-6203023598ed 
h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE=
 k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod 
h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 rsc.io/binaryregexp v0.2.0/go.mod 
h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 
h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
diff --git a/pkg/profiling/task/network/enums.go 
b/pkg/profiling/task/network/enums.go
index 2f5981f..5cbbe5f 100644
--- a/pkg/profiling/task/network/enums.go
+++ b/pkg/profiling/task/network/enums.go
@@ -124,3 +124,10 @@ func (c ConnectionProtocol) String() string {
                return unknown
        }
 }
+
+type GoTLSArgsLocationType uint32
+
+const (
+       GoTLSArgsLocationTypeStack    GoTLSArgsLocationType = 1
+       GoTLSArgsLocationTypeRegister GoTLSArgsLocationType = 2
+)
diff --git a/pkg/profiling/task/network/linker.go 
b/pkg/profiling/task/network/linker.go
index c2d8396..36995d2 100644
--- a/pkg/profiling/task/network/linker.go
+++ b/pkg/profiling/task/network/linker.go
@@ -26,7 +26,10 @@ import (
        "os"
        "sync"
 
+       "golang.org/x/arch/x86/x86asm"
+
        "github.com/apache/skywalking-rover/pkg/tools"
+       "github.com/apache/skywalking-rover/pkg/tools/elf"
 
        "github.com/cilium/ebpf"
        "github.com/cilium/ebpf/link"
@@ -88,7 +91,7 @@ func NewLinker() *Linker {
 type UProbeExeFile struct {
        addr     string
        found    bool
-       liker    *Linker
+       linker   *Linker
        realFile *link.Executable
 }
 
@@ -183,50 +186,138 @@ func (m *Linker) OpenUProbeExeFile(path string) 
*UProbeExeFile {
        return &UProbeExeFile{
                found:    true,
                addr:     path,
-               liker:    m,
+               linker:   m,
                realFile: executable,
        }
 }
 
-func (m *UProbeExeFile) AddLink(symbol string, enter, exit *ebpf.Program) {
-       m.AddLinkWithType(symbol, true, enter)
-       m.AddLinkWithType(symbol, false, exit)
+func (u *UProbeExeFile) AddLink(symbol string, enter, exit *ebpf.Program) {
+       u.AddLinkWithType(symbol, true, enter)
+       u.AddLinkWithType(symbol, false, exit)
+}
+
+func (u *UProbeExeFile) AddGoLink(symbol string, enter, exit *ebpf.Program, 
elfFile *elf.File) {
+       u.AddGoLinkWithType(symbol, true, enter, elfFile)
+       u.AddGoLinkWithType(symbol, false, exit, elfFile)
 }
 
-func (m *UProbeExeFile) AddLinkWithType(symbol string, enter bool, p 
*ebpf.Program) {
-       if !m.found {
+func (u *UProbeExeFile) AddLinkWithType(symbol string, enter bool, p 
*ebpf.Program) {
+       if !u.found {
                return
        }
-       var t string
-       if enter {
-               t = "enter"
-       } else {
-               t = "exit"
+       lk, err := u.addLinkWithType0(symbol, enter, p, 0)
+       if err != nil {
+               u.linker.errors = multierror.Append(u.linker.errors, 
fmt.Errorf("file: %s, symbol: %s, type: %s, error: %v",
+                       u.addr, symbol, u.parseEnterOrExitString(enter), err))
+       } else if lk != nil {
+               log.Debugf("attach to the uprobe, file: %s, symbol: %s, type: 
%s", u.addr, symbol, u.parseEnterOrExitString(enter))
+               u.linker.closers = append(u.linker.closers, lk)
        }
+}
 
+func (u *UProbeExeFile) addLinkWithType0(symbol string, enter bool, p 
*ebpf.Program, customizeOffset uint64) (link.Link, error) {
        // check already linked
-       uprobeIdentity := fmt.Sprintf("%s_%s_%t", m.addr, symbol, enter)
-       if m.liker.linkedUProbes[uprobeIdentity] {
-               log.Debugf("the uprobe already attached, so ignored. file: %s, 
symbol: %s, type: %s", m.addr, symbol, t)
-               return
+       uprobeIdentity := fmt.Sprintf("%s_%s_%t_%d", u.addr, symbol, enter, 
customizeOffset)
+       if u.linker.linkedUProbes[uprobeIdentity] {
+               log.Debugf("the uprobe already attached, so ignored. file: %s, 
symbol: %s, type: %s", u.addr, symbol,
+                       u.parseEnterOrExitString(enter))
+               return nil, nil
        }
-       m.liker.linkedUProbes[uprobeIdentity] = true
+       u.linker.linkedUProbes[uprobeIdentity] = true
 
        var fun func(symbol string, prog *ebpf.Program, opts 
*link.UprobeOptions) (link.Link, error)
        if enter {
-               fun = m.realFile.Uprobe
+               fun = u.realFile.Uprobe
        } else {
-               fun = m.realFile.Uretprobe
+               fun = u.realFile.Uretprobe
+       }
+
+       var opts *link.UprobeOptions
+       if customizeOffset > 0 {
+               opts = &link.UprobeOptions{
+                       Offset: customizeOffset,
+               }
+       }
+       return fun(symbol, p, opts)
+}
+
+func (u *UProbeExeFile) AddGoLinkWithType(symbol string, enter bool, p 
*ebpf.Program, elfFile *elf.File) {
+       // if is entered type of probe, then same with the other programs
+       if enter {
+               u.AddLinkWithType(symbol, enter, p)
+               return
        }
 
-       lk, err := fun(symbol, p, nil)
+       links, err := u.addGoExitLink0(symbol, p, elfFile)
        if err != nil {
-               m.liker.errors = multierror.Append(m.liker.errors, 
fmt.Errorf("file: %s, symbol: %s, type: %s, error: %v",
-                       m.addr, symbol, t, err))
+               u.linker.errors = multierror.Append(u.linker.errors, 
fmt.Errorf("file: %s, symbol: %s, type: %s, error: %v",
+                       u.addr, symbol, u.parseEnterOrExitString(enter), err))
        } else {
-               log.Debugf("attach to the uprobe, file: %s, symbol: %s, type: 
%s", m.addr, symbol, t)
-               m.liker.closers = append(m.liker.closers, lk)
+               log.Debugf("attach to the go uprobe, file: %s, symbol: %s, 
type: %s", u.addr, symbol, u.parseEnterOrExitString(enter))
+               for _, l := range links {
+                       u.linker.closers = append(u.linker.closers, l)
+               }
+       }
+}
+
+func (u *UProbeExeFile) addGoExitLink0(symbol string, p *ebpf.Program, elfFile 
*elf.File) ([]link.Link, error) {
+       // find the symbol
+       targetSymbol := elfFile.FindSymbol(symbol)
+       if targetSymbol == nil {
+               return nil, fmt.Errorf("could not found the symbol")
+       }
+
+       // find the symbol real data buffer
+       buffer, err := elfFile.ReadSymbolData(".text", targetSymbol.Location, 
targetSymbol.Size)
+       if err != nil {
+               return nil, fmt.Errorf("reading symbol data error: %v", err)
+       }
+
+       // find the base offset
+       targetBaseOffset := 
elfFile.FindBaseOffsetForAttach(targetSymbol.Location)
+       if targetBaseOffset == 0 {
+               return nil, fmt.Errorf("could not found the symbol base 
address")
+       }
+
+       // based on the base offset and symbol data buffer
+       // calculate all RET addresses
+       // https://github.com/iovisor/bcc/issues/1320#issuecomment-407927542
+       var offsets []uint64
+       for i := 0; i < int(targetSymbol.Size); {
+               inst, err := x86asm.Decode(buffer[i:], 64)
+               if err != nil {
+                       return nil, fmt.Errorf("error decode the function data: 
%v", err)
+               }
+
+               if inst.Op == x86asm.RET {
+                       offsets = append(offsets, targetBaseOffset+uint64(i))
+               }
+
+               i += inst.Len
+       }
+
+       if len(offsets) == 0 {
+               return nil, fmt.Errorf("could not found any return offsets")
+       }
+       log.Debugf("found reuturn offsets of the symbol, symbol: %s, size: %d", 
symbol, len(offsets))
+
+       var result []link.Link
+       for _, offset := range offsets {
+               l, err := u.addLinkWithType0(symbol, true, p, offset)
+               if err != nil {
+                       return nil, err
+               }
+               result = append(result, l)
+               log.Debugf("attach to the return probe of the go program, 
symbol: %s, offset: %d", symbol, offset)
+       }
+       return result, nil
+}
+
+func (u *UProbeExeFile) parseEnterOrExitString(enter bool) string {
+       if enter {
+               return "enter"
        }
+       return "exit"
 }
 
 func (m *Linker) HasError() error {
diff --git a/pkg/profiling/task/network/ssl.go 
b/pkg/profiling/task/network/ssl.go
index ab69f96..0f5944e 100644
--- a/pkg/profiling/task/network/ssl.go
+++ b/pkg/profiling/task/network/ssl.go
@@ -18,20 +18,31 @@
 package network
 
 import (
+       "bytes"
+       "encoding/binary"
        "fmt"
        "os/exec"
        "regexp"
        "strconv"
        "strings"
 
-       "github.com/apache/skywalking-rover/pkg/tools/profiling"
-
        "github.com/apache/skywalking-rover/pkg/tools"
-
+       "github.com/apache/skywalking-rover/pkg/tools/elf"
+       "github.com/apache/skywalking-rover/pkg/tools/host"
        "github.com/apache/skywalking-rover/pkg/tools/path"
+       "github.com/apache/skywalking-rover/pkg/tools/profiling"
 )
 
-var openSSLVersionRegex = 
regexp.MustCompile(`^OpenSSL\s+(?P<Major>\d)\.(?P<Minor>\d)\.(?P<Fix>\d+)\w+`)
+var (
+       openSSLVersionRegex  = 
regexp.MustCompile(`^OpenSSL\s+(?P<Major>\d)\.(?P<Minor>\d)\.(?P<Fix>\d+)\w+`)
+       goVersionRegex       = 
regexp.MustCompile(`^go(?P<Major>\d)\.(?P<Minor>\d+)`)
+       goTLSWriteSymbol     = "crypto/tls.(*Conn).Write"
+       goTLSReadSymbol      = "crypto/tls.(*Conn).Read"
+       goTLSGIDStatusSymbol = "runtime.casgstatus"
+       goTLSPollFDSymbol    = "internal/poll.FD"
+       goTLSConnSymbol      = "crypto/tls.Conn"
+       goTLSRuntimeG        = "runtime.g"
+)
 
 type OpenSSLFdSymAddrConfigInBPF struct {
        BIOReadOffset  uint32
@@ -55,6 +66,11 @@ func addSSLProcess(pid int, bpf *bpfObjects, linker *Linker) 
error {
                return err1
        }
 
+       // GoTLS
+       if err1 := processGoProcess(pid, bpf, linker, modules); err1 != nil {
+               return err1
+       }
+
        return nil
 }
 
@@ -128,6 +144,219 @@ func processEnvoyProcess(_ int, bpf *bpfObjects, linker 
*Linker, modules []*prof
        return linker.HasError()
 }
 
+type SymbolLocation struct {
+       Type   GoTLSArgsLocationType
+       Offset uint32
+}
+
+type GoTLSSymbolAddresses struct {
+       // net.Conn addresses
+       FDSysFDOffset uint64
+       TLSConnOffset uint64
+       GIDOffset     uint64
+       TCPConnOffset uint64
+
+       // casgstatus(goroutine status change) function relate locations
+       CasgStatusGPLoc     SymbolLocation
+       CasgStatusNEWValLoc SymbolLocation
+
+       // write function relate locations
+       WriteConnectionLoc SymbolLocation
+       WriteBufferLoc     SymbolLocation
+       WriteRet0Loc       SymbolLocation
+       WriteRet1Loc       SymbolLocation
+
+       // write function relate locations
+       ReadConnectionLoc SymbolLocation
+       ReadBufferLoc     SymbolLocation
+       ReadRet0Loc       SymbolLocation
+       ReadRet1Loc       SymbolLocation
+}
+
+type GoStringInC struct {
+       Ptr  uint64
+       Size uint64
+}
+
+func processGoProcess(pid int, bpf *bpfObjects, linker *Linker, modules 
[]*profiling.Module) error {
+       // check current process is go program
+       buildVersionSymbol := searchSymbol(modules, func(a, b string) bool {
+               return a == b
+       }, "runtime.buildVersion")
+       if buildVersionSymbol == nil {
+               log.Debugf("current process is not Go program, so won't add the 
GoTLS protos. pid: %d", pid)
+               return nil
+       }
+       pidExeFile := host.GetFileInHost(fmt.Sprintf("/proc/%d/exe", pid))
+       elfFile, err := elf.NewFile(pidExeFile)
+       if err != nil {
+               return fmt.Errorf("read executable file error: %v", err)
+       }
+       defer elfFile.Close()
+
+       _, minor, err := getGoVersion(elfFile, buildVersionSymbol)
+       if err != nil {
+               return err
+       }
+
+       // generate symbol offsets
+       symbolConfig, elfFile, err := generateGOTLSSymbolOffsets(modules, pid, 
elfFile, minor)
+       if err != nil {
+               return err
+       }
+       if symbolConfig == nil || elfFile == nil {
+               return nil
+       }
+
+       // setting the locations
+       if err := bpf.GoTlsArgsSymaddrMap.Put(uint32(pid), symbolConfig); err 
!= nil {
+               return fmt.Errorf("setting the Go TLS argument location 
failure, pid: %d, error: %v", pid, err)
+       }
+
+       // uprobes
+       exeFile := linker.OpenUProbeExeFile(pidExeFile)
+       exeFile.AddLinkWithType("runtime.casgstatus", true, bpf.GoCasgstatus)
+       exeFile.AddGoLink(goTLSWriteSymbol, bpf.GoTlsWrite, bpf.GoTlsWriteRet, 
elfFile)
+       exeFile.AddGoLink(goTLSReadSymbol, bpf.GoTlsRead, bpf.GoTlsReadRet, 
elfFile)
+
+       return linker.HasError()
+}
+
+func getGoVersion(elfFile *elf.File, versionSymbol *profiling.Symbol) (major, 
minor int, err error) {
+       buffer, err := elfFile.ReadSymbolData(".data", versionSymbol.Location, 
versionSymbol.Size)
+       if err != nil {
+               return 0, 0, fmt.Errorf("reading go version struct info 
failure: %v", err)
+       }
+       var t = GoStringInC{}
+       buf := bytes.NewReader(buffer)
+       err = binary.Read(buf, binary.LittleEndian, &t)
+       if err != nil {
+               return 0, 0, fmt.Errorf("read the go structure failure: %v", 
err)
+       }
+       buffer, err = elfFile.ReadSymbolData(".data", t.Ptr, t.Size)
+       if err != nil {
+               return 0, 0, fmt.Errorf("read the go version failure: %v", err)
+       }
+
+       // parse versions
+       submatch := goVersionRegex.FindStringSubmatch(string(buffer))
+       if len(submatch) != 3 {
+               return 0, 0, fmt.Errorf("the go version is failure to identify, 
version: %s", string(buffer))
+       }
+       major, err = strconv.Atoi(submatch[1])
+       if err != nil {
+               return 0, 0, fmt.Errorf("the marjor version is a number, 
version: %s", string(buffer))
+       }
+       minor, err = strconv.Atoi(submatch[2])
+       if err != nil {
+               return 0, 0, fmt.Errorf("the minor version is a number, 
version: %s", string(buffer))
+       }
+
+       return major, minor, nil
+}
+
+func generateGOTLSSymbolOffsets(modules []*profiling.Module, _ int, elfFile 
*elf.File, minorVersion int) (*GoTLSSymbolAddresses, *elf.File, error) {
+       reader, err := elfFile.NewDwarfReader(
+               goTLSReadSymbol, goTLSWriteSymbol, goTLSGIDStatusSymbol,
+               goTLSPollFDSymbol, goTLSConnSymbol, goTLSRuntimeG)
+       if err != nil {
+               return nil, nil, err
+       }
+
+       symbolAddresses := &GoTLSSymbolAddresses{}
+
+       sym := searchSymbol(modules, func(a, b string) bool {
+               return a == b
+       }, "go.itab.*net.TCPConn,net.Conn")
+       if sym == nil {
+               return nil, nil, fmt.Errorf("could found the tcp connection 
symbol")
+       }
+       symbolAddresses.TCPConnOffset = sym.Location
+
+       readFunction := reader.GetFunction(goTLSReadSymbol)
+       if readFunction == nil {
+               log.Warnf("could not found the go tls read symbol: %s", 
goTLSReadSymbol)
+               return nil, nil, nil
+       }
+       writeFunction := reader.GetFunction(goTLSWriteSymbol)
+       if writeFunction == nil {
+               log.Warnf("could not found the go tls write symbol: %s", 
goTLSWriteSymbol)
+               return nil, nil, nil
+       }
+       gidStatusFunction := reader.GetFunction(goTLSGIDStatusSymbol)
+       if gidStatusFunction == nil {
+               log.Warnf("could not found the goid status change symbol: %s", 
goTLSGIDStatusSymbol)
+               return nil, nil, nil
+       }
+
+       var retValArg0, retValArg1 = "~r1", "~r2"
+       if minorVersion >= 18 {
+               retValArg0, retValArg1 = "~r0", "~r1"
+       }
+
+       // build the symbols
+       var assignError error
+       // offset
+       assignError = assignGoTLSStructureOffset(assignError, reader, 
goTLSPollFDSymbol, "Sysfd", &symbolAddresses.FDSysFDOffset)
+       assignError = assignGoTLSStructureOffset(assignError, reader, 
goTLSConnSymbol, "conn", &symbolAddresses.TLSConnOffset)
+       assignError = assignGoTLSStructureOffset(assignError, reader, 
goTLSRuntimeG, "goid", &symbolAddresses.GIDOffset)
+
+       // gid status change
+       assignError = assignGoTLSArgsLocation(assignError, gidStatusFunction, 
"gp", &symbolAddresses.CasgStatusGPLoc)
+       assignError = assignGoTLSArgsLocation(assignError, gidStatusFunction, 
"newval", &symbolAddresses.CasgStatusNEWValLoc)
+
+       // write
+       assignError = assignGoTLSArgsLocation(assignError, writeFunction, "c", 
&symbolAddresses.WriteConnectionLoc)
+       assignError = assignGoTLSArgsLocation(assignError, writeFunction, "b", 
&symbolAddresses.WriteBufferLoc)
+       assignError = assignGoTLSArgsLocation(assignError, writeFunction, 
retValArg0, &symbolAddresses.WriteRet0Loc)
+       assignError = assignGoTLSArgsLocation(assignError, writeFunction, 
retValArg1, &symbolAddresses.WriteRet1Loc)
+       // read
+       assignError = assignGoTLSArgsLocation(assignError, readFunction, "c", 
&symbolAddresses.ReadConnectionLoc)
+       assignError = assignGoTLSArgsLocation(assignError, readFunction, "b", 
&symbolAddresses.ReadBufferLoc)
+       assignError = assignGoTLSArgsLocation(assignError, readFunction, 
retValArg0, &symbolAddresses.ReadRet0Loc)
+       assignError = assignGoTLSArgsLocation(assignError, readFunction, 
retValArg1, &symbolAddresses.ReadRet1Loc)
+
+       return symbolAddresses, elfFile, assignError
+}
+
+func assignGoTLSStructureOffset(err error, reader *elf.DwarfReader, 
structName, fieldName string, dest *uint64) error {
+       if err != nil {
+               return err
+       }
+       structure := reader.GetStructure(structName)
+       if structure == nil {
+               return fmt.Errorf("the structure is not found, name: %s", 
structName)
+       }
+       field := structure.GetField(fieldName)
+       if field == nil {
+               return fmt.Errorf("the field is not found in structure, 
structure name: %s, field name: %s", structName, fieldName)
+       }
+       *dest = uint64(field.Offset)
+       return nil
+}
+
+func assignGoTLSArgsLocation(err error, function *elf.FunctionInfo, argName 
string, dest *SymbolLocation) error {
+       if err != nil {
+               return err
+       }
+       var kSPOffset uint32 = 8
+       args := function.Args(argName)
+       if args == nil {
+               return fmt.Errorf("the args is not found, function: %s, args 
name: %s", function.Name(), argName)
+       }
+       if args.Location.Type == elf.ArgLocationTypeStack {
+               dest.Type = GoTLSArgsLocationTypeStack
+               dest.Offset = uint32(args.Location.Offset) + kSPOffset
+       } else if args.Location.Type == elf.ArgLocationTypeRegister {
+               dest.Type = GoTLSArgsLocationTypeRegister
+               dest.Offset = uint32(args.Location.Offset)
+       } else {
+               return fmt.Errorf("the location type is not support, function: 
%s, args name: %s, type: %d",
+                       function.Name(), argName, args.Location.Type)
+       }
+       return nil
+}
+
 func findProcessModules(modules []*profiling.Module, moduleNames ...string) 
(map[string]*profiling.Module, error) {
        result := make(map[string]*profiling.Module)
        for _, mod := range modules {
@@ -191,3 +420,18 @@ func buildSSLSymAddrConfig(libcryptoPath string) 
(*OpenSSLFdSymAddrConfigInBPF,
        }
        return nil, fmt.Errorf("could not fount the version of the 
libcrypto.so")
 }
+
+type stringVerify func(a, b string) bool
+
+func searchSymbol(modules []*profiling.Module, verify stringVerify, values 
...string) *profiling.Symbol {
+       for _, mod := range modules {
+               for _, s := range mod.Symbols {
+                       for _, validator := range values {
+                               if verify(s.Name, validator) {
+                                       return s
+                               }
+                       }
+               }
+       }
+       return nil
+}
diff --git a/pkg/tools/elf/abi.go b/pkg/tools/elf/abi.go
new file mode 100644
index 0000000..de34660
--- /dev/null
+++ b/pkg/tools/elf/abi.go
@@ -0,0 +1,146 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+import (
+       "fmt"
+       "strings"
+)
+
+type ArgLocation struct {
+       Type   LocationType
+       Offset uint64
+}
+
+type ArgumentLocator interface {
+       // GetLocation of the argument
+       GetLocation(typeClass TypeClass, typeSize uint64, alignmentSize uint64, 
primitivesCount int, isRetArg bool) (*ArgLocation, error)
+}
+
+func NewArgumentLocator(r *DwarfReader) ArgumentLocator {
+       if r.language == ReaderLanguageGolang {
+               // is register-based ABI
+               // example: "Go cmd/comile go1.18; regabi"
+               if strings.Contains(r.producer, "regabi") {
+                       return newGolangRegisterLocator()
+               }
+               return &GolangStackLocator{}
+       }
+       return &UnknownLocator{language: r.language}
+}
+
+type GolangRegisterLocator struct {
+       curStackOffset       uint64
+       curIntArgOffset      uint64
+       curFloatArgOffset    uint64
+       curIntRetArgOffset   uint64
+       curFloatRetArgOffset uint64
+
+       intArgRegisters      []RegisterName
+       floatArgRegisters    []RegisterName
+       intRetArgRegisters   []RegisterName
+       floatRetArgRegisters []RegisterName
+}
+
+func newGolangRegisterLocator() *GolangRegisterLocator {
+       intRegisters := []RegisterName{
+               RegisterNameRAX, RegisterNameRBX, RegisterNameRCX,
+               RegisterNameRDI, RegisterNameRSI, RegisterNameR8,
+               RegisterNameR9, RegisterNameR10, RegisterNameR11,
+       }
+       floatRegisters := []RegisterName{
+               RegisterNameXMM0, RegisterNameXMM1, RegisterNameXMM2,
+               RegisterNameXMM3, RegisterNameXMM4, RegisterNameXMM5,
+               RegisterNameXMM6, RegisterNameXMM7, RegisterNameXMM8,
+               RegisterNameXMM9, RegisterNameXMM10, RegisterNameXMM11,
+               RegisterNameXMM12, RegisterNameXMM13, RegisterNameXMM14,
+       }
+       return &GolangRegisterLocator{
+               intArgRegisters:      intRegisters,
+               floatArgRegisters:    floatRegisters,
+               intRetArgRegisters:   intRegisters,
+               floatRetArgRegisters: floatRegisters,
+       }
+}
+
+func (g *GolangRegisterLocator) GetLocation(typeClass TypeClass, typeSize, 
alignmentSize uint64, primitivesCount int,
+       isRetArg bool) (*ArgLocation, error) {
+       var registers []RegisterName
+       var offset *uint64
+       if typeClass == TypeClassInteger {
+               if isRetArg {
+                       registers = g.intRetArgRegisters
+                       offset = &g.curIntRetArgOffset
+               } else {
+                       registers = g.intArgRegisters
+                       offset = &g.curIntArgOffset
+               }
+       } else if typeClass == TypeClassFloat {
+               if isRetArg {
+                       registers = g.floatRetArgRegisters
+                       offset = &g.curFloatRetArgOffset
+               } else {
+                       registers = g.floatArgRegisters
+                       offset = &g.curFloatArgOffset
+               }
+       } else {
+               return nil, fmt.Errorf("unsupport type classs for getting 
location, type class: %d", typeClass)
+       }
+
+       result := &ArgLocation{}
+       if primitivesCount <= len(registers) {
+               if typeClass == TypeClassInteger {
+                       result.Type = ArgLocationTypeRegister
+               } else {
+                       result.Type = ArgLocationTypeRegisterFP
+               }
+               result.Offset = *offset
+               *offset += uint64(primitivesCount * 8)
+       } else {
+               g.curStackOffset = snapUpToMultiple(g.curStackOffset, 
alignmentSize)
+               result.Type = ArgLocationTypeStack
+               result.Offset = g.curStackOffset
+
+               g.curStackOffset += typeSize
+       }
+       return result, nil
+}
+
+type GolangStackLocator struct {
+       curStackOffset uint64
+}
+
+func (g *GolangStackLocator) GetLocation(_ TypeClass, _, alignmentSize uint64, 
_ int, _ bool) (*ArgLocation, error) {
+       g.curStackOffset = snapUpToMultiple(g.curStackOffset, alignmentSize)
+       result := &ArgLocation{}
+       result.Type = ArgLocationTypeStack
+       result.Offset = g.curStackOffset
+       return result, nil
+}
+
+type UnknownLocator struct {
+       language int
+}
+
+func (u *UnknownLocator) GetLocation(typeClass TypeClass, typeSize, 
alignmentSize uint64, primitivesCount int, isRetArg bool) (*ArgLocation, error) 
{
+       return nil, fmt.Errorf("unknown locator for language: %d", u.language)
+}
+
+func snapUpToMultiple(curSize, alignmentSize uint64) uint64 {
+       return (curSize + (alignmentSize-1)/alignmentSize) * alignmentSize
+}
diff --git a/pkg/tools/elf/dwarf.go b/pkg/tools/elf/dwarf.go
new file mode 100644
index 0000000..a899842
--- /dev/null
+++ b/pkg/tools/elf/dwarf.go
@@ -0,0 +1,83 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+import (
+       "debug/dwarf"
+       "encoding/binary"
+       "fmt"
+)
+
+var ReaderLanguageGolang = 22
+
+type DwarfReader struct {
+       elfByteOrder binary.ByteOrder
+
+       producer   string
+       language   int
+       functions  map[string]*FunctionInfo
+       structures map[string]*StructureInfo
+}
+
+func (f *File) NewDwarfReader(attrNames ...string) (*DwarfReader, error) {
+       data, err := f.realFile.DWARF()
+       if err != nil {
+               return nil, err
+       }
+       reader := &DwarfReader{}
+       if err := reader.init(data, attrNames); err != nil {
+               return nil, err
+       }
+       return reader, nil
+}
+
+func (r *DwarfReader) GetFunction(name string) *FunctionInfo {
+       return r.functions[name]
+}
+
+func (r *DwarfReader) GetStructure(name string) *StructureInfo {
+       return r.structures[name]
+}
+
+func (r *DwarfReader) init(data *dwarf.Data, readAttrNames []string) error {
+       r.functions = make(map[string]*FunctionInfo)
+       r.structures = make(map[string]*StructureInfo)
+
+       reader := data.Reader()
+       r.elfByteOrder = reader.ByteOrder()
+       for {
+               entry, err := reader.Next()
+               if err != nil {
+                       return fmt.Errorf("read dwarf error: %v", err)
+               }
+               if entry == nil {
+                       break
+               }
+
+               if err := r.processProducer(data, entry); err != nil {
+                       return err
+               }
+               if err := r.processFunctions(readAttrNames, data, entry); err 
!= nil {
+                       return err
+               }
+               if err := r.processStructure(readAttrNames, data, entry); err 
!= nil {
+                       return err
+               }
+       }
+       return nil
+}
diff --git a/pkg/tools/elf/dwarf_init.go b/pkg/tools/elf/dwarf_init.go
new file mode 100644
index 0000000..cdfce40
--- /dev/null
+++ b/pkg/tools/elf/dwarf_init.go
@@ -0,0 +1,293 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+import (
+       "debug/dwarf"
+       "fmt"
+)
+
+func (r *DwarfReader) processProducer(_ *dwarf.Data, entry *dwarf.Entry) error 
{
+       if entry.Tag != dwarf.TagCompileUnit {
+               return nil
+       }
+
+       producer, ok := entry.Val(dwarf.AttrProducer).(string)
+       if !ok {
+               return fmt.Errorf("the producer field not exists")
+       }
+       language, ok := entry.Val(dwarf.AttrLanguage).(int64)
+       if !ok {
+               return fmt.Errorf("the language field not exists")
+       }
+       r.producer = producer
+       r.language = int(language)
+       return nil
+}
+
+func (r *DwarfReader) processFunctions(funcNames []string, data *dwarf.Data, 
entry *dwarf.Entry) error {
+       if entry.Tag != dwarf.TagSubprogram {
+               return nil
+       }
+
+       name, ok := entry.Val(dwarf.AttrName).(string)
+       if !ok {
+               return nil
+       }
+
+       // the function is need to read
+       found := false
+       for _, n := range funcNames {
+               if n == name {
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               return nil
+       }
+       args, err := r.getFunctionArgs(data, entry)
+       if err != nil {
+               return err
+       }
+
+       r.functions[name] = &FunctionInfo{
+               name: name,
+               args: args,
+       }
+       return nil
+}
+
+func (r *DwarfReader) processStructure(names []string, data *dwarf.Data, entry 
*dwarf.Entry) error {
+       if entry.Tag != dwarf.TagStructType {
+               return nil
+       }
+
+       name, ok := entry.Val(dwarf.AttrName).(string)
+       if !ok {
+               return nil
+       }
+
+       found := false
+       for _, n := range names {
+               if n == name {
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               return nil
+       }
+
+       fields, err := r.getStructureFields(data, entry)
+       if err != nil {
+               return err
+       }
+
+       r.structures[name] = &StructureInfo{
+               name:   name,
+               fields: fields,
+       }
+       return nil
+}
+
+func (r *DwarfReader) entryType(data *dwarf.Data, entry *dwarf.Entry) 
(dwarf.Type, error) {
+       off, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
+       if !ok {
+               return nil, nil
+       }
+       return data.Type(off)
+}
+
+func (r *DwarfReader) IsRetArgs(entry *dwarf.Entry) (bool, error) {
+       isRet, ok := entry.Val(dwarf.AttrVarParam).(bool)
+       if !ok {
+               return false, nil
+       }
+       return isRet, nil
+}
+
+func (r *DwarfReader) getStructureFields(data *dwarf.Data, entry *dwarf.Entry) 
([]*StructureFieldInfo, error) {
+       reader := data.Reader()
+
+       reader.Seek(entry.Offset)
+       _, err := reader.Next()
+       if err != nil {
+               return nil, err
+       }
+
+       res := make([]*StructureFieldInfo, 0)
+       for {
+               child, err := reader.Next()
+               if err != nil {
+                       return nil, err
+               }
+               if child == nil || child.Tag == 0 {
+                       break
+               }
+
+               if child.Tag != dwarf.TagMember {
+                       continue
+               }
+
+               name, ok := child.Val(dwarf.AttrName).(string)
+               if !ok {
+                       continue
+               }
+               offset, ok := child.Val(dwarf.AttrDataMemberLoc).(int64)
+               if !ok {
+                       continue
+               }
+
+               field := &StructureFieldInfo{
+                       Name:   name,
+                       Offset: offset,
+               }
+               res = append(res, field)
+       }
+       return res, nil
+}
+
+func (r *DwarfReader) getFunctionArgs(data *dwarf.Data, entry *dwarf.Entry) 
(map[string]*FunctionArgsInfo, error) {
+       reader := data.Reader()
+
+       reader.Seek(entry.Offset)
+       _, err := reader.Next()
+       if err != nil {
+               return nil, err
+       }
+
+       locator := NewArgumentLocator(r)
+       args := make(map[string]*FunctionArgsInfo)
+       for {
+               child, err := reader.Next()
+               if err != nil {
+                       return nil, err
+               }
+               if child == nil || child.Tag == 0 {
+                       break
+               }
+
+               if child.Tag != dwarf.TagFormalParameter {
+                       continue
+               }
+               name, ok := child.Val(dwarf.AttrName).(string)
+               if !ok {
+                       continue
+               }
+               if existsArgs := args[name]; existsArgs != nil {
+                       continue
+               }
+
+               curArgs := &FunctionArgsInfo{}
+               // data type
+               dtyp, err := r.entryType(data, child)
+               if err != nil {
+                       return nil, err
+               }
+               curArgs.tp = dtyp
+
+               // Is return value
+               if r.language == ReaderLanguageGolang {
+                       isRet, err1 := r.IsRetArgs(child)
+                       if err1 != nil {
+                               return nil, err1
+                       }
+                       curArgs.IsRet = isRet
+               }
+
+               // get location
+               typeClass := r.getArgTypeClass(child, dtyp)
+               byteSize := r.getArgTypeByteSize(child, dtyp)
+               alignmentByteSize := r.getArgAlignmentByteSize(child, dtyp)
+               primitiveFieldCount := r.getPrimitiveFieldCount(child, dtyp)
+               location, err := locator.GetLocation(typeClass, byteSize, 
alignmentByteSize, primitiveFieldCount, curArgs.IsRet)
+               if err != nil {
+                       return nil, err
+               }
+               curArgs.Location = location
+
+               args[name] = curArgs
+       }
+
+       return args, nil
+}
+
+func (r *DwarfReader) getArgTypeClass(_ *dwarf.Entry, tp dwarf.Type) TypeClass 
{
+       switch val := tp.(type) {
+       case *dwarf.FloatType:
+               return TypeClassFloat
+       case *dwarf.StructType:
+               res := TypeClassNone
+               for _, field := range val.Field {
+                       memberType := r.getArgTypeClass(nil, field.Type)
+                       res = res.Combine(memberType)
+               }
+               return res
+       default:
+               return TypeClassInteger
+       }
+}
+
+func (r *DwarfReader) getArgTypeByteSize(_ *dwarf.Entry, tp dwarf.Type) uint64 
{
+       basicType, ok := tp.(*dwarf.BasicType)
+       if ok {
+               return uint64(basicType.ByteSize)
+       }
+
+       switch val := tp.(type) {
+       case *dwarf.StructType:
+               return uint64(val.ByteSize)
+       default:
+               return 8
+       }
+}
+
+func (r *DwarfReader) getArgAlignmentByteSize(_ *dwarf.Entry, tp dwarf.Type) 
uint64 {
+       basicType, ok := tp.(*dwarf.BasicType)
+       if ok {
+               return uint64(basicType.ByteSize)
+       }
+
+       switch val := tp.(type) {
+       case *dwarf.StructType:
+               var maxSize uint64 = 1
+               for _, field := range val.Field {
+                       curSize := r.getArgAlignmentByteSize(nil, field.Type)
+                       if curSize > maxSize {
+                               maxSize = curSize
+                       }
+               }
+               return maxSize
+       default:
+               return 8
+       }
+}
+
+func (r *DwarfReader) getPrimitiveFieldCount(_ *dwarf.Entry, tp dwarf.Type) 
int {
+       structType, ok := tp.(*dwarf.StructType)
+       if ok {
+               totalCount := 0
+               for _, field := range structType.Field {
+                       totalCount += r.getPrimitiveFieldCount(nil, field.Type)
+               }
+               return totalCount
+       }
+
+       return 1
+}
diff --git a/pkg/tools/elf/elf.go b/pkg/tools/elf/elf.go
new file mode 100644
index 0000000..57ece5d
--- /dev/null
+++ b/pkg/tools/elf/elf.go
@@ -0,0 +1,107 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+import (
+       "debug/elf"
+       "fmt"
+       "os"
+)
+
+type File struct {
+       path     string
+       realFile *elf.File
+}
+
+type Symbol struct {
+       Name     string
+       Location uint64
+       Size     uint64
+}
+
+func NewFile(path string) (*File, error) {
+       f, err := elf.Open(path)
+       if err != nil {
+               return nil, err
+       }
+       return &File{
+               path:     path,
+               realFile: f,
+       }, nil
+}
+
+func (f *File) Close() error {
+       return f.realFile.Close()
+}
+
+func (f *File) FindSymbol(name string) *Symbol {
+       symbols, _ := f.realFile.Symbols()
+       dynamicSymbols, _ := f.realFile.DynamicSymbols()
+       if len(symbols) == 0 && len(dynamicSymbols) == 0 {
+               return nil
+       }
+       symbols = append(symbols, dynamicSymbols...)
+       for _, s := range symbols {
+               if s.Name == name {
+                       return &Symbol{
+                               Name:     name,
+                               Location: s.Value,
+                               Size:     s.Size,
+                       }
+               }
+       }
+       return nil
+}
+
+func (f *File) ReadSymbolData(section string, offset, size uint64) ([]byte, 
error) {
+       elfSection := f.realFile.Section(section)
+       if elfSection == nil {
+               return nil, fmt.Errorf("could not found the \"%s\" section in 
elf file", section)
+       }
+
+       dataOffset := offset - elfSection.Addr + elfSection.Offset
+       realFile, err := os.Open(f.path)
+       if err != nil {
+               return nil, err
+       }
+       defer realFile.Close()
+       _, err = realFile.Seek(int64(dataOffset), 0)
+       if err != nil {
+               return nil, fmt.Errorf("seek file error: %v", err)
+       }
+
+       buffer := make([]byte, size)
+       _, err = realFile.Read(buffer)
+       if err != nil {
+               return nil, fmt.Errorf("reading symbol data error: %v", err)
+       }
+       return buffer, nil
+}
+
+func (f *File) FindBaseOffsetForAttach(symbolLocation uint64) uint64 {
+       for _, prog := range f.realFile.Progs {
+               if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
+                       continue
+               }
+
+               if prog.Vaddr <= symbolLocation && symbolLocation < 
(prog.Vaddr+prog.Memsz) {
+                       return symbolLocation - prog.Vaddr + prog.Off
+               }
+       }
+       return 0
+}
diff --git a/pkg/tools/elf/enums.go b/pkg/tools/elf/enums.go
new file mode 100644
index 0000000..9e4b967
--- /dev/null
+++ b/pkg/tools/elf/enums.go
@@ -0,0 +1,87 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+type TypeClass int
+
+const (
+       TypeClassNone    TypeClass = 0
+       TypeClassInteger TypeClass = 1
+       TypeClassFloat   TypeClass = 2
+       TypeClassMixed   TypeClass = 3
+)
+
+func (c TypeClass) Combine(other TypeClass) TypeClass {
+       if c == TypeClassMixed || other == TypeClassMixed {
+               return TypeClassMixed
+       }
+       if c == TypeClassNone {
+               return other
+       }
+       if other == TypeClassNone {
+               return c
+       }
+
+       if c != other {
+               return TypeClassMixed
+       }
+       return c
+}
+
+type LocationType uint64
+
+const (
+       ArgLocationTypeUnknown    LocationType = 0
+       ArgLocationTypeStack      LocationType = 1 // frame stack pointer
+       ArgLocationTypeStackBP    LocationType = 2 // frame base pointer
+       ArgLocationTypeRegister   LocationType = 3 // integer register
+       ArgLocationTypeRegisterFP LocationType = 4 // float-point register
+)
+
+type RegisterName int
+
+const (
+       // for int type class
+       RegisterNameRAX RegisterName = 0
+       RegisterNameRBX RegisterName = 1
+       RegisterNameRCX RegisterName = 2
+       RegisterNameRDX RegisterName = 3
+       RegisterNameRDI RegisterName = 4
+       RegisterNameRSI RegisterName = 5
+       RegisterNameR8  RegisterName = 6
+       RegisterNameR9  RegisterName = 7
+       RegisterNameR10 RegisterName = 8
+       RegisterNameR11 RegisterName = 9
+
+       // for float type class
+       RegisterNameXMM0  RegisterName = 100
+       RegisterNameXMM1  RegisterName = 101
+       RegisterNameXMM2  RegisterName = 102
+       RegisterNameXMM3  RegisterName = 103
+       RegisterNameXMM4  RegisterName = 104
+       RegisterNameXMM5  RegisterName = 105
+       RegisterNameXMM6  RegisterName = 106
+       RegisterNameXMM7  RegisterName = 107
+       RegisterNameXMM8  RegisterName = 108
+       RegisterNameXMM9  RegisterName = 109
+       RegisterNameXMM10 RegisterName = 110
+       RegisterNameXMM11 RegisterName = 111
+       RegisterNameXMM12 RegisterName = 112
+       RegisterNameXMM13 RegisterName = 113
+       RegisterNameXMM14 RegisterName = 114
+)
diff --git a/pkg/tools/elf/function.go b/pkg/tools/elf/function.go
new file mode 100644
index 0000000..1882974
--- /dev/null
+++ b/pkg/tools/elf/function.go
@@ -0,0 +1,39 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+import "debug/dwarf"
+
+type FunctionInfo struct {
+       name string
+       args map[string]*FunctionArgsInfo
+}
+
+func (f *FunctionInfo) Name() string {
+       return f.name
+}
+
+func (f *FunctionInfo) Args(name string) *FunctionArgsInfo {
+       return f.args[name]
+}
+
+type FunctionArgsInfo struct {
+       tp       dwarf.Type
+       IsRet    bool
+       Location *ArgLocation
+}
diff --git a/pkg/tools/elf/structure.go b/pkg/tools/elf/structure.go
new file mode 100644
index 0000000..1b5cf6b
--- /dev/null
+++ b/pkg/tools/elf/structure.go
@@ -0,0 +1,37 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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
+//
+//     http://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.
+
+package elf
+
+type StructureInfo struct {
+       name   string
+       fields []*StructureFieldInfo
+}
+
+func (s *StructureInfo) GetField(name string) *StructureFieldInfo {
+       for _, f := range s.fields {
+               if f.Name == name {
+                       return f
+               }
+       }
+       return nil
+}
+
+type StructureFieldInfo struct {
+       Name   string
+       Offset int64
+}
diff --git a/pkg/tools/profiling/api.go b/pkg/tools/profiling/api.go
index 32f2fb8..0c25e2b 100644
--- a/pkg/tools/profiling/api.go
+++ b/pkg/tools/profiling/api.go
@@ -62,6 +62,7 @@ type ModuleRange struct {
 type Symbol struct {
        Name     string
        Location uint64
+       Size     uint64
 }
 
 type StatFinder interface {
diff --git a/pkg/tools/profiling/go_library.go 
b/pkg/tools/profiling/go_library.go
index 2257b2a..f6a7cf0 100644
--- a/pkg/tools/profiling/go_library.go
+++ b/pkg/tools/profiling/go_library.go
@@ -62,7 +62,7 @@ func (l *GoLibrary) AnalyzeSymbols(filePath string) 
([]*Symbol, error) {
        // adapt symbol struct
        data := make([]*Symbol, len(symbols))
        for i, sym := range symbols {
-               data[i] = &Symbol{Name: sym.Name, Location: sym.Value}
+               data[i] = &Symbol{Name: sym.Name, Location: sym.Value, Size: 
sym.Size}
        }
 
        sort.SliceStable(data, func(i, j int) bool {
diff --git a/pkg/tools/profiling/kernel.go b/pkg/tools/profiling/kernel.go
index 95cee54..51a75c4 100644
--- a/pkg/tools/profiling/kernel.go
+++ b/pkg/tools/profiling/kernel.go
@@ -63,6 +63,7 @@ func (k *KernelFinder) Analyze(filepath string) (*Info, 
error) {
                symbols = append(symbols, &Symbol{
                        Name:     info[2],
                        Location: atoi,
+                       Size:     0,
                })
        }
 

Reply via email to