Skip to content

Commit

Permalink
Allow parsing go 1.20-1.21 pclntab (#3947)
Browse files Browse the repository at this point in the history
  • Loading branch information
wargio authored Nov 2, 2023
1 parent fde0358 commit 33c47ca
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 11 deletions.
7 changes: 6 additions & 1 deletion librz/bin/p/bin_pe.inc
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,20 @@ static bool is_go_pclntab(ut8 *magic) {
#define IS_GOPCLNTAB_1_16_BE(x) (x[3] == 0xfa && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff && x[4] == 0x00 && x[5] == 0x00)
#define IS_GOPCLNTAB_1_18_LE(x) (x[0] == 0xf0 && x[1] == 0xff && x[2] == 0xff && x[3] == 0xff && x[4] == 0x00 && x[5] == 0x00)
#define IS_GOPCLNTAB_1_18_BE(x) (x[3] == 0xf0 && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff && x[4] == 0x00 && x[5] == 0x00)
#define IS_GOPCLNTAB_1_20_LE(x) (x[0] == 0xf1 && x[1] == 0xff && x[2] == 0xff && x[3] == 0xff && x[4] == 0x00 && x[5] == 0x00)
#define IS_GOPCLNTAB_1_20_BE(x) (x[3] == 0xf1 && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff && x[4] == 0x00 && x[5] == 0x00)
return IS_GOPCLNTAB_1_2_LE(magic) || IS_GOPCLNTAB_1_2_BE(magic) ||
IS_GOPCLNTAB_1_16_LE(magic) || IS_GOPCLNTAB_1_16_BE(magic) ||
IS_GOPCLNTAB_1_18_LE(magic) || IS_GOPCLNTAB_1_18_BE(magic);
IS_GOPCLNTAB_1_18_LE(magic) || IS_GOPCLNTAB_1_18_BE(magic) ||
IS_GOPCLNTAB_1_20_LE(magic) || IS_GOPCLNTAB_1_20_BE(magic);
#undef IS_GOPCLNTAB_1_2_LE
#undef IS_GOPCLNTAB_1_2_BE
#undef IS_GOPCLNTAB_1_16_LE
#undef IS_GOPCLNTAB_1_16_BE
#undef IS_GOPCLNTAB_1_18_LE
#undef IS_GOPCLNTAB_1_18_BE
#undef IS_GOPCLNTAB_1_20_LE
#undef IS_GOPCLNTAB_1_20_BE
}

static ut64 find_go_pclntab(RzBinFile *bf, ut32 *size, ut64 *vaddr) {
Expand Down
45 changes: 35 additions & 10 deletions librz/core/golang.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
#define GO_1_2 (12)
#define GO_1_16 (116)
#define GO_1_18 (118)
#define GO_1_20 (120)

#define IS_GOPCLNTAB_1_2_LE(x) (x[0] == 0xfb && x[1] == 0xff && x[2] == 0xff && x[3] == 0xff)
#define IS_GOPCLNTAB_1_2_BE(x) (x[3] == 0xfb && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff)
#define IS_GOPCLNTAB_1_16_LE(x) (x[0] == 0xfa && x[1] == 0xff && x[2] == 0xff && x[3] == 0xff)
#define IS_GOPCLNTAB_1_16_BE(x) (x[3] == 0xfa && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff)
#define IS_GOPCLNTAB_1_18_LE(x) (x[0] == 0xf0 && x[1] == 0xff && x[2] == 0xff && x[3] == 0xff)
#define IS_GOPCLNTAB_1_18_BE(x) (x[3] == 0xf0 && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff)
#define IS_GOPCLNTAB_1_20_LE(x) (x[0] == 0xf1 && x[1] == 0xff && x[2] == 0xff && x[3] == 0xff)
#define IS_GOPCLNTAB_1_20_BE(x) (x[3] == 0xf1 && x[2] == 0xff && x[1] == 0xff && x[0] == 0xff)

typedef struct go_pc_line_table_t {
RzIO *io;
Expand Down Expand Up @@ -101,6 +104,21 @@ ut64 go_data(GoPcLnTab *pclntab, ut32 n_word) {
return pclntab->vaddr + offset;
}

static const char *pclntab_version_str(GoPcLnTab *pclntab) {
switch (pclntab->version) {
case GO_1_2:
return "go 1.2";
case GO_1_16:
return "go 1.16-1.17";
case GO_1_18:
return "go 1.18-1.19";
case GO_1_20:
return "go 1.20-1.21";
default:
return "go unknown";
}
}

#define is_addr_outside(x) ((x) <= begin || (x) >= end)
static bool is_pclntab_valid(GoPcLnTab *pclntab) {
ut64 begin = pclntab->vaddr + 8;
Expand Down Expand Up @@ -158,8 +176,9 @@ static void add_new_func_symbol(RzCore *core, const char *name, ut64 vaddr) {
}
}

static ut32 core_recover_golang_functions_go_1_18(RzCore *core, GoPcLnTab *pclntab) {
rz_core_notify_done(core, "Found go 1.18 pclntab data.");
static ut32 core_recover_golang_functions_go_1_18_plus(RzCore *core, GoPcLnTab *pclntab) {
const char *go_ver = pclntab_version_str(pclntab);
rz_core_notify_done(core, "Found %s pclntab data.", go_ver);
ut8 tmp8[8];
char name[256];
char *flag = NULL;
Expand All @@ -178,7 +197,7 @@ static ut32 core_recover_golang_functions_go_1_18(RzCore *core, GoPcLnTab *pclnt
pclntab->ptrsize = 4; // GO 1.18+ uses ut32 words.

if (!is_pclntab_valid(pclntab)) {
rz_core_notify_error(core, "Invalid go 1.18 pclntab (invalid table).");
rz_core_notify_error(core, "Invalid %s pclntab (invalid table).", go_ver);
return 0;
}

Expand Down Expand Up @@ -234,7 +253,8 @@ static ut32 core_recover_golang_functions_go_1_18(RzCore *core, GoPcLnTab *pclnt
}

static ut32 core_recover_golang_functions_go_1_16(RzCore *core, GoPcLnTab *pclntab) {
rz_core_notify_done(core, "Found go 1.16 pclntab data.");
const char *go_ver = pclntab_version_str(pclntab);
rz_core_notify_done(core, "Found %s pclntab data.", go_ver);
ut8 tmp8[8];
char name[256];
char *flag = NULL;
Expand All @@ -252,7 +272,7 @@ static ut32 core_recover_golang_functions_go_1_16(RzCore *core, GoPcLnTab *pclnt
pclntab->functabsize = ((pclntab->nfunctab * 2) + 1) * go_func_tab_field_size(pclntab);

if (!is_pclntab_valid(pclntab)) {
rz_core_notify_error(core, "Invalid go 1.16 pclntab (invalid table).");
rz_core_notify_error(core, "Invalid %s pclntab (invalid table).", go_ver);
return 0;
}

Expand Down Expand Up @@ -311,7 +331,8 @@ static ut32 core_recover_golang_functions_go_1_16(RzCore *core, GoPcLnTab *pclnt

// Valid for golang 1.2 -> 1.15
static ut32 core_recover_golang_functions_go_1_2(RzCore *core, GoPcLnTab *pclntab) {
rz_core_notify_done(core, "Found go 1.12 pclntab data.");
const char *go_ver = pclntab_version_str(pclntab);
rz_core_notify_done(core, "Found %s pclntab data.", go_ver);
ut8 tmp8[8];
char name[256];
char *flag = NULL;
Expand Down Expand Up @@ -339,7 +360,7 @@ static ut32 core_recover_golang_functions_go_1_2(RzCore *core, GoPcLnTab *pclnta
pclntab->nfiletab = rz_read_ble32(tmp8, pclntab->big_endian);

if (!is_pclntab_valid(pclntab)) {
rz_core_notify_error(core, "Invalid go 1.12 pclntab (invalid table).");
rz_core_notify_error(core, "Invalid %s pclntab (invalid table).", go_ver);
return 0;
}

Expand Down Expand Up @@ -472,10 +493,14 @@ RZ_API bool rz_core_analysis_recover_golang_functions(RzCore *core) {
pclntab.quantum = header[6];
pclntab.ptrsize = header[7];

if (IS_GOPCLNTAB_1_18_BE(header) || IS_GOPCLNTAB_1_18_LE(header)) {
if (IS_GOPCLNTAB_1_20_BE(header) || IS_GOPCLNTAB_1_20_LE(header)) {
pclntab.version = GO_1_20;
pclntab.big_endian = IS_GOPCLNTAB_1_20_BE(header);
num_syms = core_recover_golang_functions_go_1_18_plus(core, &pclntab);
} else if (IS_GOPCLNTAB_1_18_BE(header) || IS_GOPCLNTAB_1_18_LE(header)) {
pclntab.version = GO_1_18;
pclntab.big_endian = IS_GOPCLNTAB_1_18_BE(header);
num_syms = core_recover_golang_functions_go_1_18(core, &pclntab);
num_syms = core_recover_golang_functions_go_1_18_plus(core, &pclntab);
} else if (IS_GOPCLNTAB_1_16_BE(header) || IS_GOPCLNTAB_1_16_LE(header)) {
pclntab.version = GO_1_16;
pclntab.big_endian = IS_GOPCLNTAB_1_16_BE(header);
Expand All @@ -486,7 +511,7 @@ RZ_API bool rz_core_analysis_recover_golang_functions(RzCore *core) {
num_syms = core_recover_golang_functions_go_1_2(core, &pclntab);
} else {
ut32 magic = rz_read_be32(header);
rz_core_notify_error(core, "Invalid go pclntab (unknown version: 0x%x).", magic);
rz_core_notify_error(core, "Invalid go pclntab (unknown version: 0x%x). Please open an issue.", magic);
return false;
}

Expand Down
60 changes: 60 additions & 0 deletions test/db/analysis/golang
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,63 @@ EXPECT=<<EOF
| 0x00099edc auipc t0, 0x3e ; 0xbd602 ; "expected 'foo' or 'bar' subcommandsfile type does not support deadlinefindrunnable: netpoll with spinninggreyobject: obj not poi"
EOF
RUN

NAME=Resolve all symbols on a stripped windows go1.21 binary
FILE=bins/golang/go-re-sample-windows-amd64-go121.exe
CMDS=<<EOF
aalg
fl~sym.go.~?
pdfs @ main ~str.
izq~?
EOF
EXPECT=<<EOF
1604
0x00490237 str.foo
0x00490292 str.enable
0x004902a0 str.enable
0x004902b0 str.name
0x004902c0 str.name
0x004902f2 str.bar
0x0049034d str.level
0x0049035b str.level
0x00490448 str.subcommand__bar
0x00490495 str.level:
0x0049051d str.tail:
0x004905c2 str.subcommand__foo
0x00490615 str.enable:
0x00490692 str.name:
0x0049071e str.tail:
0x00490780 str.expected__foo__or__bar__subcommands
20633
EOF
RUN

NAME=Resolve all symbols on a stripped linux go1.21 binary
FILE=bins/golang/go-re-sample-linux-amd64-go121
CMDS=<<EOF
aalg
fl~sym.go.~?
pdfs @ main ~str.
izq~?
EOF
EXPECT=<<EOF
1587
0x004875b7 str.foo
0x00487612 str.enable
0x00487620 str.enable
0x00487630 str.name
0x00487640 str.name
0x00487672 str.bar
0x004876cd str.level
0x004876db str.level
0x004877c8 str.subcommand__bar
0x00487815 str.level:
0x0048789d str.tail:
0x00487942 str.subcommand__foo
0x00487995 str.enable:
0x00487a12 str.name:
0x00487a9e str.tail:
0x00487b00 str.expected__foo__or__bar__subcommands
3558
EOF
RUN

0 comments on commit 33c47ca

Please sign in to comment.