Skip to content

Commit

Permalink
Add binary output option (-b) to kstool (keystone-engine#453)
Browse files Browse the repository at this point in the history
* Add binary output option (-b) to kstool

Using -b option, kstool will print the encoded instructions to stdout
in binary format.

For example:

```
kstool -b arm64 "CCMP X0, X1, 4, EQ" 0xcafebaba | xxd
00000000: 0400 41fa                                ..A.
```

For `getopt`, this commit reuse the getopt.c from capstone-engine.

* Fix build for MSVC
  • Loading branch information
el poto rico authored Jun 13, 2020
1 parent 274a3d5 commit c1f6742
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 20 deletions.
7 changes: 6 additions & 1 deletion kstool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ project(kstool)

include_directories("../include")

add_executable(kstool kstool.cpp)
if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
include_directories("./")
add_executable(kstool getopt.c kstool.cpp)
else()
add_executable(kstool kstool.cpp)
endif()

target_link_libraries(kstool keystone)

Expand Down
79 changes: 79 additions & 0 deletions kstool/getopt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
extern "C" {

#include <string.h>
#include <stdio.h>

#include "getopt.h"

int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
const char *optarg; /* argument associated with option */

#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""

/*
* getopt --
* Parse argc/argv argument vector.
*/
int getopt (int nargc, char * const nargv[], const char *ostr)
{
static const char *place = EMSG; /* option letter processing */
const char *oli; /* option letter list index */

if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}

if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */

if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr (ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':')
(void)printf ("illegal option -- %c\n", optopt);
return (BADCH);
}

if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
} else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)printf ("option requires an argument -- %c\n", optopt);
return (BADCH);
} else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}

return optopt; /* dump back option letter */
}

} // end extern "C"
18 changes: 18 additions & 0 deletions kstool/getopt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
extern "C" {

#ifndef KSTOOL_GETOPT_H
#define KSTOOL_GETOPT_H

// global
extern int opterr, /* if error message should be printed */
optind, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */

extern const char *optarg; /* argument associated with option */

int getopt (int nargc, char *const nargv[], const char *ostr);

#endif

} // end extern "C"
68 changes: 49 additions & 19 deletions kstool/kstool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@

#include <keystone/keystone.h>

#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
#include "getopt.h"
#endif

static void usage(char *prog)
{
printf("Kstool v%u.%u.%u for Keystone Assembler Engine (www.keystone-engine.org)\nBy Nguyen Anh Quynh, 2016-2018\n\n",
KS_VERSION_MAJOR, KS_VERSION_MINOR, KS_VERSION_EXTRA);
printf("Syntax: %s <arch+mode> <assembly-string> [start-address-in-hex-format]\n", prog);
printf("Syntax: %s [-b] <arch+mode> <assembly-string> [start-address-in-hex-format]\n", prog);
printf("\nThe following <arch+mode> options are supported:\n");

if (ks_arch_supported(KS_ARCH_X86)) {
Expand Down Expand Up @@ -79,7 +83,8 @@ static void usage(char *prog)
printf(" evm: Ethereum Virtual Machine\n");
}

printf("\n");
printf("\nExtra options:\n");
printf(" -b binary output\n\n");
}

int main(int argc, char **argv)
Expand All @@ -92,15 +97,33 @@ int main(int argc, char **argv)
size_t count;
unsigned char *insn = NULL;
size_t size;

if (argc == 2) {
bool binary_output = false;
int c;
int args_left;

while ((c = getopt(argc, argv, "bh")) != -1) {
switch (c) {
case 'b':
binary_output = true;
break;
case 'h':
usage(argv[0]);
return 0;
default:
usage(argv[0]);
return -1;
}
}

args_left = argc - optind;
if (args_left == 1) {
// handle code from stdin
#if !defined(WIN32) && !defined(WIN64) && !defined(_WIN32) && !defined(_WIN64)
int flags;
size_t index = 0;
char buf[1024];

mode = argv[1];
mode = argv[optind];

if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) == -1)
flags = 0;
Expand Down Expand Up @@ -129,17 +152,17 @@ int main(int argc, char **argv)
usage(argv[0]);
return -1;
#endif
} else if (argc == 3) {
} else if (args_left == 2) {
// kstool <arch> <assembly>
mode = argv[1];
assembly = argv[2];
} else if (argc == 4) {
mode = argv[optind];
assembly = argv[optind + 1];
} else if (args_left == 3) {
// kstool <arch> <assembly> <address>
char *temp;
mode = argv[1];
assembly = argv[2];
start_addr = strtoull(argv[3], &temp, 16);
if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
mode = argv[optind];
assembly = argv[optind + 1];
start_addr = strtoull(argv[optind + 2], &temp, 16);
if (temp == argv[optind + 2] || *temp != '\0' || errno == ERANGE) {
printf("ERROR: invalid address argument, quit!\n");
return -2;
}
Expand Down Expand Up @@ -293,13 +316,20 @@ int main(int argc, char **argv)
if (ks_asm(ks, assembly, start_addr, &insn, &size, &count)) {
printf("ERROR: failed on ks_asm() with count = %zu, error = '%s' (code = %u)\n", count, ks_strerror(ks_errno(ks)), ks_errno(ks));
} else {
size_t i;
printf("%s = [ ", assembly);
for (i = 0; i < size; i++) {
printf("%02x ", insn[i]);
if (binary_output) {
size_t i;
for (i = 0; i < size; ++i) {
putchar(insn[i]);
}
} else {
size_t i;
printf("%s = [ ", assembly);
for (i = 0; i < size; i++) {
printf("%02x ", insn[i]);
}
printf("]\n");
//printf("Assembled: %lu bytes, %lu statement(s)\n", size, count);
}
printf("]\n");
//printf("Assembled: %lu bytes, %lu statement(s)\n", size, count);
}

// NOTE: free insn after usage to avoid leaking memory
Expand Down

0 comments on commit c1f6742

Please sign in to comment.