Dtrace from C does not yield same profiling result compared to command line - dtrace

I want to programmatically trace stacks from C for Node.js (JS addresses aside).
The following command gives me stacks with resolved c++ symbols.
sudo dtrace -C -n 'profile-101 /pid == 13221/ { ustack() }'
The following C code only returns addresses for Node's C/C++ code. What would be the equivalent?
#include <dtrace.h>
#include <signal.h>
#include <stdio.h>
struct ps_prochandle *g_pr;
static dtrace_hdl_t* g_dtp;
static int chewrec (const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) {
// A NULL rec indicates that we've processed the last record.
if (rec == NULL) {
return (DTRACE_CONSUME_NEXT);
}
return (DTRACE_CONSUME_THIS);
}
static const char* g_prog =
"#pragma D option switchrate=1000hz\n"
"profile-1ms /pid == 13221/ {\n"
"ustack();\n"
"}";
static int g_intr;
static int g_exited;
static void intr (int signo) {
g_intr = 1;
}
int main (int argc, char** argv) {
int err;
if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
fprintf(stderr, "failed to initialize dtrace: %s\n", dtrace_errmsg(NULL, err));
return -1;
}
printf("Dtrace initialized\n");
(void) dtrace_setopt(g_dtp, "bufsize", "4m");
(void) dtrace_setopt(g_dtp, "aggsize", "4m");
printf("dtrace options set\n");
dtrace_prog_t* prog;
if ((prog = dtrace_program_strcompile(g_dtp, g_prog, DTRACE_PROBESPEC_NAME, DTRACE_C_CPP, 0, NULL)) == NULL) {
fprintf(stderr, "failed to compile dtrace program\n");
return -1;
} else {
printf("dtrace program compiled\n");
}
dtrace_proginfo_t info;
if (dtrace_program_exec(g_dtp, prog, &info) == -1) {
fprintf(stderr, "failed to enable dtrace probes\n");
return -1;
} else {
printf("dtrace probes enabled\n");
}
struct sigaction act;
(void) sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = intr;
(void) sigaction(SIGINT, &act, NULL);
(void) sigaction(SIGTERM, &act, NULL);
if (dtrace_go(g_dtp) != 0) {
fprintf(stderr, "could not start instrumentation\n");
return -1;
} else {
printf("instrumentation started ..\n");
}
int done = 0;
do {
if (!g_intr && !done) {
dtrace_sleep(g_dtp);
}
if (done || g_intr || g_exited) {
done = 1;
if (dtrace_stop(g_dtp) == -1) {
fprintf(stderr, "could not stop tracing\n");
return -1;
}
}
switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
case DTRACE_WORKSTATUS_DONE:
done = 1;
break;
case DTRACE_WORKSTATUS_OKAY:
break;
default:
fprintf(stderr, "processing aborted");
return -1;
}
} while (!done);
printf("closing dtrace\n");
dtrace_close(g_dtp);
return 0;
}

From the dtrace-Mailing list, Robert Mustacchi:
TL;DR resolve symbols yourself in userland.
"So, all the symbol resolution processing is always done in user land. In
other words, DTrace in the kernel only ever gathers addresses like
you're seeing for the cases where you're using ustack and not a ustack
handler via the jstack() action (jstack() also only returns symbols for
non-native frames). Note that if you want to see the JavaScript specific
symbols in addition to the native ones, you'll want to be using jstack()
in your examples and not ustack().
The way that these you can perform these mappings will change depending
on what system you're on. If you look at what DTrace does on illumos for
printing the results of ustack()
(http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libdtrace/common/dt_consume.c#1320),
then you'll see that it uses libproc and the Plookup_by_addr() function
to perform the translation. Though it's worth pointing out that neither
are stable interfaces, though they seldom change."

Related

Creating a history function for a Unix Shell

Here is what my program currently looks like. I have to add history functionality that gets stored in a file 'mysh.history'. Currently I expect my output to simply append each user command in my shell to the file.
first line of output
first line of output
It only appends the first input into the shell instance. I think my problem lies with my understanding of the fork() process but I'm not sure what is going on. Any suggestions?
#define MYSH_BUFFERSIZE 64
#define MYSH_DELIM " \t\n"
fstream file;
// custom function declarations
int mysh_exit(char **args);
int mysh_add_history(char **args);
int mysh_history(char **);
char byebye[] = "byebye";
char exit_program[] = "exit";
char history[] = "history";
// contains names of all custom shell commands implemented
char *lookup_str[] = {byebye, exit_program, history};
// holds references to all commands in lookup_str[]
// order or commands must match each other
int (*lookup_func[])(char **) = {
&mysh_exit,
&mysh_exit,
&mysh_history
};
/* custom shell commands implementations BEGIN*/
// Without the argument, it prints out the recently typed commands (with their
// arguments), in reverse order, with numbers
// If the argument “-c” is passed, it clears the list of recently typed commands.
void clear_history()
{
file.close();
file.open("mysh.history", ios::trunc);
}
int mysh_add_history(char *line)
{
// if exists then append to the history
if (access("mysh.history", F_OK) == 0)
{
file.open("mysh.history", ios::app);
}
// otherwise create mysh.history and start writing
else
{
file.open("mysh.history", ios::out);
}
file << line << "\n";
return 0;
}
int mysh_history(char **)
{
return 0;
}
int mysh_exit(char **args)
{
return 0;
}
int num_commands()
{
return sizeof(lookup_str) / sizeof(char *);
}
/* custom shell functions END*/
/* main shell processes BEGIN*/
// returns the tokens (arguments) array after tokenizing line from mysh_read_line()
char **mysh_split_args(char *line)
{
int buffer_size = MYSH_BUFFERSIZE;
int current_pos = 0;
char **tokens = (char **)malloc(buffer_size * sizeof(char *));
char *tok;
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
tok = strtok(line, MYSH_DELIM);
while (tok != NULL)
{
tokens[current_pos] = tok;
current_pos++;
if (current_pos >= buffer_size)
{
buffer_size += MYSH_BUFFERSIZE;
tokens = (char **)realloc(tokens, buffer_size * sizeof(char *));
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
}
tok = strtok(NULL, MYSH_DELIM);
}
tokens[current_pos] = NULL;
return tokens;
}
// mysh_read_line allocates MYSH_BUFFER_SIZE of memory to the intial buffer
// it reallocates memory as needed with getLine() function
// returns line to be processed and tokenized by mysh_split_args()
char *mysh_read_line(void)
{
char *line = NULL;
size_t buffersize = 0;
// getLine() also needs to check for EOF after in the case of text files being read.
if (getline(&line, &buffersize, stdin) == -1)
{
if (feof(stdin))
{
exit(EXIT_SUCCESS);
}
else
{
printf("failed to read line\n");
exit(EXIT_FAILURE);
}
}
return line;
}
// args passed comes from mysh_split_args()
int mysh_launch_process(char **args)
{
pid_t pid;
pid_t wpid;
int state;
pid = fork();
// if we enter child process
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
printf("error in mysh\n");
}
exit(EXIT_FAILURE);
}
// forking failed
else if (pid < 0)
{
printf("error in mysh\n");
}
else
{
// if we enter parent process
do
{
wpid = waitpid(pid, &state, WUNTRACED);
} while (!WIFEXITED(state) && !WIFSIGNALED(state));
}
return 1;
}
// calls mysh_launch_process() and handles programs being called
int mysh_execute(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < num_commands(); i++)
{
if (strcmp(args[0], lookup_str[i]) == 0)
{
if (strcmp(args[0], "history") == 0 && strcmp(args[1], "-c"))
{
clear_history();
}
return (*lookup_func[i])(args);
}
}
return mysh_launch_process(args);
}
void mysh_loop(void)
{
char *line;
char **args;
int state;
do
{
printf("# ");
line = mysh_read_line();
mysh_add_history(line);
args = mysh_split_args(line);
state = mysh_execute(args);
free(line);
free(args);
} while (state);
}
int main(int argc, char **argv)
{
// run main program loop
mysh_loop();
file.close();
return EXIT_SUCCESS;
}
/* main shell processes END*/```

config.h: No such file or directory in ssh_client from libssh's example

When I compile ssh_client code from example folder of libssh source directory( I have wrote about building process of this library in this link : libssh's functions couldn't be found on qt):
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "examples_common.h"
#define MAXCMD 10
static char *host = NULL;
static char *user = NULL;
static char *cmds[MAXCMD];
static char *config_file = NULL;
static struct termios terminal;
static char *pcap_file = NULL;
static char *proxycommand;
static int auth_callback(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata)
{
(void) verify;
(void) userdata;
return ssh_getpass(prompt, buf, len, echo, verify);
}
struct ssh_callbacks_struct cb = {
.auth_function = auth_callback,
.userdata = NULL,
};
static void add_cmd(char *cmd)
{
int n;
for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
if (n == MAXCMD) {
return;
}
cmds[n] = strdup(cmd);
}
static void usage(void)
{
fprintf(stderr,
"Usage : ssh [options] [login#]hostname\n"
"sample client - libssh-%s\n"
"Options :\n"
" -l user : log in as user\n"
" -p port : connect to port\n"
" -d : use DSS to verify host public key\n"
" -r : use RSA to verify host public key\n"
" -F file : parse configuration file instead of default one\n"
#ifdef WITH_PCAP
" -P file : create a pcap debugging file\n"
#endif
#ifndef _WIN32
" -T proxycommand : command to execute as a socket proxy\n"
#endif
"\n",
ssh_version(0));
exit(0);
}
static int opts(int argc, char **argv)
{
int i;
while((i = getopt(argc,argv,"T:P:F:")) != -1) {
switch(i){
case 'P':
pcap_file = optarg;
break;
case 'F':
config_file = optarg;
break;
#ifndef _WIN32
case 'T':
proxycommand = optarg;
break;
#endif
default:
fprintf(stderr, "Unknown option %c\n", optopt);
usage();
}
}
if (optind < argc) {
host = argv[optind++];
}
while(optind < argc) {
add_cmd(argv[optind++]);
}
if (host == NULL) {
usage();
}
return 0;
}
#ifndef HAVE_CFMAKERAW
static void cfmakeraw(struct termios *termios_p)
{
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
}
#endif
static void do_cleanup(int i)
{
/* unused variable */
(void) i;
tcsetattr(0, TCSANOW, &terminal);
}
static void do_exit(int i)
{
/* unused variable */
(void) i;
do_cleanup(0);
exit(0);
}
static ssh_channel chan;
static int signal_delayed = 0;
static void sigwindowchanged(int i)
{
(void) i;
signal_delayed = 1;
}
static void setsignal(void)
{
signal(SIGWINCH, sigwindowchanged);
signal_delayed = 0;
}
static void sizechanged(void)
{
struct winsize win = {
.ws_row = 0,
};
ioctl(1, TIOCGWINSZ, &win);
ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
setsignal();
}
static void select_loop(ssh_session session,ssh_channel channel)
{
ssh_connector connector_in, connector_out, connector_err;
int rc;
ssh_event event = ssh_event_new();
/* stdin */
connector_in = ssh_connector_new(session);
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
ssh_connector_set_in_fd(connector_in, 0);
ssh_event_add_connector(event, connector_in);
/* stdout */
connector_out = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_out, 1);
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
ssh_event_add_connector(event, connector_out);
/* stderr */
connector_err = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_err, 2);
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
ssh_event_add_connector(event, connector_err);
while (ssh_channel_is_open(channel)) {
if (signal_delayed) {
sizechanged();
}
rc = ssh_event_dopoll(event, 60000);
if (rc == SSH_ERROR) {
fprintf(stderr, "Error in ssh_event_dopoll()\n");
break;
}
}
ssh_event_remove_connector(event, connector_in);
ssh_event_remove_connector(event, connector_out);
ssh_event_remove_connector(event, connector_err);
ssh_connector_free(connector_in);
ssh_connector_free(connector_out);
ssh_connector_free(connector_err);
ssh_event_free(event);
}
static void shell(ssh_session session)
{
ssh_channel channel;
struct termios terminal_local;
int interactive=isatty(0);
channel = ssh_channel_new(session);
if (channel == NULL) {
return;
}
if (interactive) {
tcgetattr(0, &terminal_local);
memcpy(&terminal, &terminal_local, sizeof(struct termios));
}
if (ssh_channel_open_session(channel)) {
printf("Error opening channel : %s\n", ssh_get_error(session));
ssh_channel_free(channel);
return;
}
chan = channel;
if (interactive) {
ssh_channel_request_pty(channel);
sizechanged();
}
if (ssh_channel_request_shell(channel)) {
printf("Requesting shell : %s\n", ssh_get_error(session));
ssh_channel_free(channel);
return;
}
if (interactive) {
cfmakeraw(&terminal_local);
tcsetattr(0, TCSANOW, &terminal_local);
setsignal();
}
signal(SIGTERM, do_cleanup);
select_loop(session, channel);
if (interactive) {
do_cleanup(0);
}
ssh_channel_free(channel);
}
static void batch_shell(ssh_session session)
{
ssh_channel channel;
char buffer[1024];
size_t i;
int s = 0;
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
s += snprintf(buffer + s, sizeof(buffer) - s, "%s ", cmds[i]);
free(cmds[i]);
cmds[i] = NULL;
}
channel = ssh_channel_new(session);
if (channel == NULL) {
return;
}
ssh_channel_open_session(channel);
if (ssh_channel_request_exec(channel, buffer)) {
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
ssh_channel_free(channel);
return;
}
select_loop(session, channel);
ssh_channel_free(channel);
}
static int client(ssh_session session)
{
int auth = 0;
char *banner;
int state;
if (user) {
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
return -1;
}
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
return -1;
}
if (proxycommand != NULL) {
if (ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand)) {
return -1;
}
}
/* Parse configuration file if specified: The command-line options will
* overwrite items loaded from configuration file */
if (config_file != NULL) {
ssh_options_parse_config(session, config_file);
} else {
ssh_options_parse_config(session, NULL);
}
if (ssh_connect(session)) {
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
return -1;
}
state = verify_knownhost(session);
if (state != 0) {
return -1;
}
ssh_userauth_none(session, NULL);
banner = ssh_get_issue_banner(session);
if (banner) {
printf("%s\n", banner);
free(banner);
}
auth = authenticate_console(session);
if (auth != SSH_AUTH_SUCCESS) {
return -1;
}
if (cmds[0] == NULL) {
shell(session);
} else {
batch_shell(session);
}
return 0;
}
static ssh_pcap_file pcap;
static void set_pcap(ssh_session session)
{
if (pcap_file == NULL) {
return;
}
pcap = ssh_pcap_file_new();
if (pcap == NULL) {
return;
}
if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
printf("Error opening pcap file\n");
ssh_pcap_file_free(pcap);
pcap = NULL;
return;
}
ssh_set_pcap_file(session, pcap);
}
static void cleanup_pcap(void)
{
if (pcap != NULL) {
ssh_pcap_file_free(pcap);
}
pcap = NULL;
}
int main(int argc, char **argv)
{
ssh_session session;
session = ssh_new();
ssh_callbacks_init(&cb);
ssh_set_callbacks(session,&cb);
if (ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr,
"Error parsing command line: %s\n",
ssh_get_error(session));
usage();
}
opts(argc, argv);
signal(SIGTERM, do_exit);
set_pcap(session);
client(session);
ssh_disconnect(session);
ssh_free(session);
cleanup_pcap();
ssh_finalize();
return 0;
}
I got the following error:
/home/heydari.f/projects/ssh_client/ssh_client/main.c:100: error: config.h: No such file or directory
#include "config.h"
^~~~~~~~~~
Is there anything to do with configure or what?
I use Qt and my os is ubuntu 18.04.
Config headers as config.h normally aren't needed to compile a program against a library. Those are generated to compile the library, not the programs that link against them. If not, there will be lot of trouble as lots of software use them and there would be lots of collisions between them.
Being an example, it may be that it uses the config.h, but in that case I'm pretty sure you should compile with the system libssh uses to compile. (You may need to specify an option to compile examples when calling configure or specify something in DefineOptions.cmake or something in the same line.)
If you copied the sources (as it seems as the error states projects/ssh_client/) to build with Qt, you probably can remove that include unless it is a config from Qt itself.
Also, if you are compiling with Qt you surely need to install the lib and follow #Dmitry advice about -I, -L and -l flags to compiler.

V8 "segmentation fault (core dumped)" Error Displayed By Sample Shell Application

V8 Version: 8.2.0
OS: Ubuntu v18.04.3 LTS
Architecture: x64
What steps will reproduce the problem?
Followed instructions on https://v8.dev/docs/source-code and https://v8.dev/docs/build to build and compile v8
Compiled the shell.cc in samples folder
After successful compilation the shell app is executed
What is the expected output?
shell application should work just like the d8 shell application. In the d8 shell when the enter key is clicked the d8 shell prompt is returned and d8 shell does not exit the application.
What do you see instead?
When I hit the enter key I get the error "Segmentation fault (Core Dump)" and the shell app exits.
Code in the shell.cc is below. Same as the code in the v8 samples folder at https://github.com/v8/v8/blob/master/samples/shell.cc
#include <include/v8.h>
#include <include/libplatform/libplatform.h>
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* This sample program shows how to implement a simple javascript shell
* based on V8. This includes initializing V8 with command line options,
* creating global functions, compiling and executing strings.
*
* For a more sophisticated shell, consider using the debug shell D8.
*/
v8::Local<v8::Context> CreateShellContext(v8::Isolate* isolate);
void RunShell(v8::Local<v8::Context> context, v8::Platform* platform);
int RunMain(v8::Isolate* isolate, v8::Platform* platform, int argc,
char* argv[]);
bool ExecuteString(v8::Isolate* isolate, v8::Local<v8::String> source,
v8::Local<v8::Value> name, bool print_result,
bool report_exceptions);
void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* name);
void ReportException(v8::Isolate* isolate, v8::TryCatch* handler);
static bool run_shell;
int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
run_shell = (argc == 1);
int result;
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = CreateShellContext(isolate);
if (context.IsEmpty()) {
fprintf(stderr, "Error creating context\n");
return 1;
}
v8::Context::Scope context_scope(context);
result = RunMain(isolate, platform.get(), argc, argv);
if (run_shell) RunShell(context, platform.get());
}
isolate->Dispose();
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
return result;
}
// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
// Creates a new execution environment containing the built-in
// functions.
v8::Local<v8::Context> CreateShellContext(v8::Isolate* isolate) {
// Create a template for the global object.
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
// Bind the global 'print' function to the C++ Print callback.
global->Set(
v8::String::NewFromUtf8(isolate, "print", v8::NewStringType::kNormal)
.ToLocalChecked(),
v8::FunctionTemplate::New(isolate, Print));
// Bind the global 'read' function to the C++ Read callback.
global->Set(v8::String::NewFromUtf8(
isolate, "read", v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(isolate, Read));
// Bind the global 'load' function to the C++ Load callback.
global->Set(v8::String::NewFromUtf8(
isolate, "load", v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(isolate, Load));
// Bind the 'quit' function
global->Set(v8::String::NewFromUtf8(
isolate, "quit", v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(isolate, Quit));
// Bind the 'version' function
global->Set(
v8::String::NewFromUtf8(isolate, "version", v8::NewStringType::kNormal)
.ToLocalChecked(),
v8::FunctionTemplate::New(isolate, Version));
return v8::Context::New(isolate, NULL, global);
}
// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called. Prints its arguments on stdout separated by
// spaces and ending with a newline.
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
bool first = true;
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope(args.GetIsolate());
if (first) {
first = false;
} else {
printf(" ");
}
v8::String::Utf8Value str(args.GetIsolate(), args[i]);
const char* cstr = ToCString(str);
printf("%s", cstr);
}
printf("\n");
fflush(stdout);
}
// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called. This function loads the content of the file named in
// the argument into a JavaScript string.
void Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 1) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(), "Bad parameters",
v8::NewStringType::kNormal).ToLocalChecked());
return;
}
v8::String::Utf8Value file(args.GetIsolate(), args[0]);
if (*file == NULL) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
v8::NewStringType::kNormal).ToLocalChecked());
return;
}
v8::Local<v8::String> source;
if (!ReadFile(args.GetIsolate(), *file).ToLocal(&source)) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
v8::NewStringType::kNormal).ToLocalChecked());
return;
}
args.GetReturnValue().Set(source);
}
// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called. Loads, compiles and executes its argument
// JavaScript file.
void Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope(args.GetIsolate());
v8::String::Utf8Value file(args.GetIsolate(), args[i]);
if (*file == NULL) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
v8::NewStringType::kNormal).ToLocalChecked());
return;
}
v8::Local<v8::String> source;
if (!ReadFile(args.GetIsolate(), *file).ToLocal(&source)) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file",
v8::NewStringType::kNormal).ToLocalChecked());
return;
}
if (!ExecuteString(args.GetIsolate(), source, args[i], false, false)) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(), "Error executing file",
v8::NewStringType::kNormal).ToLocalChecked());
return;
}
}
}
// The callback that is invoked by v8 whenever the JavaScript 'quit'
// function is called. Quits.
void Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
// If not arguments are given args[0] will yield undefined which
// converts to the integer value 0.
int exit_code =
args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromMaybe(0);
fflush(stdout);
fflush(stderr);
exit(exit_code);
}
void Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(
v8::String::NewFromUtf8(args.GetIsolate(), v8::V8::GetVersion(),
v8::NewStringType::kNormal).ToLocalChecked());
}
// Reads a file into a v8 string.
v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* name) {
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::MaybeLocal<v8::String>();
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (size_t i = 0; i < size;) {
i += fread(&chars[i], 1, size - i, file);
if (ferror(file)) {
fclose(file);
return v8::MaybeLocal<v8::String>();
}
}
fclose(file);
v8::MaybeLocal<v8::String> result = v8::String::NewFromUtf8(
isolate, chars, v8::NewStringType::kNormal, static_cast<int>(size));
delete[] chars;
return result;
}
// Process remaining command line arguments and execute files
int RunMain(v8::Isolate* isolate, v8::Platform* platform, int argc,
char* argv[]) {
for (int i = 1; i < argc; i++) {
const char* str = argv[i];
if (strcmp(str, "--shell") == 0) {
run_shell = true;
} else if (strcmp(str, "-f") == 0) {
// Ignore any -f flags for compatibility with the other stand-
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
fprintf(stderr,
"Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly.
v8::Local<v8::String> file_name =
v8::String::NewFromUtf8(isolate, "unnamed",
v8::NewStringType::kNormal).ToLocalChecked();
v8::Local<v8::String> source;
if (!v8::String::NewFromUtf8(isolate, argv[++i],
v8::NewStringType::kNormal)
.ToLocal(&source)) {
return 1;
}
bool success = ExecuteString(isolate, source, file_name, false, true);
while (v8::platform::PumpMessageLoop(platform, isolate)) continue;
if (!success) return 1;
} else {
// Use all other arguments as names of files to load and run.
v8::Local<v8::String> file_name =
v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kNormal)
.ToLocalChecked();
v8::Local<v8::String> source;
if (!ReadFile(isolate, str).ToLocal(&source)) {
fprintf(stderr, "Error reading '%s'\n", str);
continue;
}
bool success = ExecuteString(isolate, source, file_name, false, true);
while (v8::platform::PumpMessageLoop(platform, isolate)) continue;
if (!success) return 1;
}
}
return 0;
}
// The read-eval-execute loop of the shell.
void RunShell(v8::Local<v8::Context> context, v8::Platform* platform) {
fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion());
static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code.
v8::Context::Scope context_scope(context);
v8::Local<v8::String> name(
v8::String::NewFromUtf8(context->GetIsolate(), "(shell)",
v8::NewStringType::kNormal).ToLocalChecked());
while (true) {
char buffer[kBufferSize];
fprintf(stderr, "> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
v8::HandleScope handle_scope(context->GetIsolate());
ExecuteString(
context->GetIsolate(),
v8::String::NewFromUtf8(context->GetIsolate(), str,
v8::NewStringType::kNormal).ToLocalChecked(),
name, true, true);
while (v8::platform::PumpMessageLoop(platform, context->GetIsolate()))
continue;
}
fprintf(stderr, "\n");
}
// Executes a string within the current v8 context.
bool ExecuteString(v8::Isolate* isolate, v8::Local<v8::String> source,
v8::Local<v8::Value> name, bool print_result,
bool report_exceptions) {
v8::HandleScope handle_scope(isolate);
v8::TryCatch try_catch(isolate);
v8::ScriptOrigin origin(name);
v8::Local<v8::Context> context(isolate->GetCurrentContext());
v8::Local<v8::Script> script;
if (!v8::Script::Compile(context, source, &origin).ToLocal(&script)) {
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(isolate, &try_catch);
return false;
} else {
v8::Local<v8::Value> result;
if (!script->Run(context).ToLocal(&result)) {
assert(try_catch.HasCaught());
// Print errors that happened during execution.
if (report_exceptions)
ReportException(isolate, &try_catch);
return false;
} else {
assert(!try_catch.HasCaught());
if (print_result && !result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(isolate, result);
const char* cstr = ToCString(str);
printf("%s\n", cstr);
}
return true;
}
}
}
void ReportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
v8::HandleScope handle_scope(isolate);
v8::String::Utf8Value exception(isolate, try_catch->Exception());
const char* exception_string = ToCString(exception);
v8::Local<v8::Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
fprintf(stderr, "%s\n", exception_string);
} else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(isolate,
message->GetScriptOrigin().ResourceName());
v8::Local<v8::Context> context(isolate->GetCurrentContext());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber(context).FromJust();
fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
v8::String::Utf8Value sourceline(
isolate, message->GetSourceLine(context).ToLocalChecked());
const char* sourceline_string = ToCString(sourceline);
fprintf(stderr, "%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn(context).FromJust();
for (int i = 0; i < start; i++) {
fprintf(stderr, " ");
}
int end = message->GetEndColumn(context).FromJust();
for (int i = start; i < end; i++) {
fprintf(stderr, "^");
}
fprintf(stderr, "\n");
v8::Local<v8::Value> stack_trace_string;
if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
stack_trace_string->IsString() &&
v8::Local<v8::String>::Cast(stack_trace_string)->Length() > 0) {
v8::String::Utf8Value stack_trace(isolate, stack_trace_string);
const char* stack_trace_string = ToCString(stack_trace);
fprintf(stderr, "%s\n", stack_trace_string);
}
}
}
Teminal Output:
➜ cd v8
➜ ./shell
V8 version 8.2.0 (candidate) [sample shell]
>
[1] 2119 segmentation fault (core dumped) ./shell
➜
tried a bug report but no response
It seems the bug is https://bugs.chromium.org/p/v8/issues/detail?id=10214; as I write this, the bug was filed 8 hours ago, and this question was asked 6 hours ago, so you waited all of 2 hours on a Sunday (where nobody is at work) until giving up?
I get the error "Segmentation fault (Core Dump)" and the shell app exits
When you get a segfault in any C/C++ program, then what you do is:
compile in Debug mode
Run in a debugger
Trigger the crash
Get a backtrace.
The backtrace will either tell you what's wrong, or at least it will provide important information for anyone who might try to help you.
And please, don't post text (including console output) as images! Neither screenshots nor actual photos are appropriate. Copy-paste the text!
FWIW, the official shell sample works just fine (I just tried: ninja -C out/x64.debug v8_shell && out/x64.debug/v8_shell). There must be something that you're doing differently, but you didn't say what that might be.

error: invalid use of non-static member function ‘int test::hotplug_callback(libusb_context*, libusb_device*, libusb_hotplug_event, void*)’

I adapted the libusb hotplug example from
* libusb example program for hotplug API
* Copyright © 2012-2013 Nathan Hjelm <hjelmn#mac.com>
(code below) as a test and put it in a class as I have the same issue with my real program.
I know that if I put static in front of the two callbacks that it functions but I don't want them to be static. I want to access my instance variables from the callbacks. The idea is that the user plugs in a usb device let's call it usbXYZ. From the callback I instantiate class usbXYZ and put in an std::map - user removes it and I remove it from the map. The class that contains the std::map with the objects in it has a 'higher level' method to write to the devices.
How do I make the callback functions work none static please? If possible do explain it a little bit because I don't understand it. Thanks.
#include <stdlib.h>
#include <stdio.h>
#include <thread>
#include "libusb-1.0/libusb.h"
class test{
public:
test() {
okGo();
}
private:
int done = 0;
libusb_device_handle *handle = NULL;
int LIBUSB_CALL hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
struct libusb_device_descriptor desc;
int rc;
(void)ctx;
(void)dev;
(void)event;
(void)user_data;
rc = libusb_get_device_descriptor(dev, &desc);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error getting device descriptor\n");
}
printf ("Device attached: %04x:%04x\n", desc.idVendor, desc.idProduct);
if (handle) {
libusb_close (handle);
handle = NULL;
}
rc = libusb_open (dev, &handle);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error opening device\n");
}
done++;
return 0;
}
int LIBUSB_CALL hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
(void)ctx;
(void)dev;
(void)event;
(void)user_data;
printf ("Device detached\n");
if (handle) {
libusb_close (handle);
handle = NULL;
}
done++;
return 0;
}
int okGo(){
libusb_hotplug_callback_handle hp[2];
int product_id, vendor_id, class_id;
int rc;
vendor_id = LIBUSB_HOTPLUG_MATCH_ANY;
product_id = LIBUSB_HOTPLUG_MATCH_ANY;
class_id = LIBUSB_HOTPLUG_MATCH_ANY;
rc = libusb_init (NULL);
if (rc < 0)
{
printf("failed to initialise libusb: %s\n", libusb_error_name(rc));
return EXIT_FAILURE;
}
if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
printf ("Hotplug capabilites are not supported on this platform\n");
libusb_exit (NULL);
return EXIT_FAILURE;
}
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, LIBUSB_HOTPLUG_ENUMERATE, vendor_id,
product_id, class_id, hotplug_callback, NULL, &hp[0]);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error registering callback 0\n");
libusb_exit (NULL);
return EXIT_FAILURE;
}
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, vendor_id,
product_id,class_id, hotplug_callback_detach, NULL, &hp[1]);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error registering callback 1\n");
libusb_exit (NULL);
return EXIT_FAILURE;
}
while (done < 20) {
//rc = libusb_handle_events (NULL);
if (libusb_handle_events_completed(nullptr, nullptr) != LIBUSB_SUCCESS)
printf("libusb_handle_events() failed: %s\n", libusb_error_name(rc));
}
if (handle) {
libusb_close (handle);
}
libusb_exit (NULL);
return EXIT_SUCCESS;
}
};
int main(int argc, char *argv[])
{
std::unique_ptr<test> testClass1 = std::make_unique<test>();
//just test
for (;;)
{
//main service loop
std::this_thread::sleep_for(std::chrono::microseconds(2000000));
}
}
libusb is a C library, it can only take non-member function pointers. The difference between a non-member function (or a static member function) pointer, and a pointer to a non-static member function is that a non-static member function needs an object to be called on, and C have no idea about C++ "objects".
With libusb you can solve it though, using static member function and the user-data pointer (which you pass a null-pointers now).
For example
class test
{
// ...
static int LIBUSB_CALL static_hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
return reinterpret_cast<test*>(user_data)->hotplug_callback_detach(ctx, dev, event);
}
int hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event)
{
// Current code
}
// ...
int okGo()
{
// ...
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, vendor_id,
product_id,class_id, static_hotplug_callback_detach, this, &hp[1]);
// ...
}
Notice that the static member function is used when registering the callback, and that this is passed as the user data pointer.

How to guarantee read() actually sends 100% of data sent by write() through named pipes

I've got the following two programs, one acting as a reader and the other as a writer. The writer seems to only send about 3/4 of the data correctly to be read by the reader. Is there any way to guarantee that all the data is being sent? I think I've got it set up so that it reads and writes reliably, but it still seems to miss 1/4 of the data.
Heres the source of the writer
#define pipe "/tmp/testPipe"
using namespace std;
queue<string> sproutFeed;
ssize_t r_write(int fd, char *buf, size_t size) {
char *bufp;
size_t bytestowrite;
ssize_t byteswritten;
size_t totalbytes;
for (bufp = buf, bytestowrite = size, totalbytes = 0;
bytestowrite > 0;
bufp += byteswritten, bytestowrite -= byteswritten) {
byteswritten = write(fd, bufp, bytestowrite);
if(errno == EPIPE)
{
signal(SIGPIPE,SIG_IGN);
}
if ((byteswritten) == -1 && (errno != EINTR))
return -1;
if (byteswritten == -1)
byteswritten = 0;
totalbytes += byteswritten;
}
return totalbytes;
}
void* sendData(void *thread_arg)
{
int fd, ret_val, count, numread;
string word;
char bufpipe[5];
ret_val = mkfifo(pipe, 0777); //make the sprout pipe
if (( ret_val == -1) && (errno != EEXIST))
{
perror("Error creating named pipe");
exit(1);
}
while(1)
{
if(!sproutFeed.empty())
{
string s;
s.clear();
s = sproutFeed.front();
int sizeOfData = s.length();
snprintf(bufpipe, 5, "%04d\0", sizeOfData);
char stringToSend[strlen(bufpipe) + sizeOfData +1];
bzero(stringToSend, sizeof(stringToSend));
strncpy(stringToSend,bufpipe, strlen(bufpipe));
strncat(stringToSend,s.c_str(),strlen(s.c_str()));
strncat(stringToSend, "\0", strlen("\0"));
int fullSize = strlen(stringToSend);
signal(SIGPIPE,SIG_IGN);
fd = open(pipe,O_WRONLY);
int numWrite = r_write(fd, stringToSend, strlen(stringToSend) );
cout << errno << endl;
if(errno == EPIPE)
{
signal(SIGPIPE,SIG_IGN);
}
if(numWrite != fullSize )
{
signal(SIGPIPE,SIG_IGN);
bzero(bufpipe, strlen(bufpipe));
bzero(stringToSend, strlen(stringToSend));
close(fd);
}
else
{
signal(SIGPIPE,SIG_IGN);
sproutFeed.pop();
close(fd);
bzero(bufpipe, strlen(bufpipe));
bzero(stringToSend, strlen(stringToSend));
}
}
else
{
if(usleep(.0002) == -1)
{
perror("sleeping error\n");
}
}
}
}
int main(int argc, char *argv[])
{
signal(SIGPIPE,SIG_IGN);
int x;
for(x = 0; x < 100; x++)
{
sproutFeed.push("All ships in the sea sink except for that blue one over there, that one never sinks. Most likley because it\'s blue and thats the mightiest colour of ship. Interesting huh?");
}
int rc, i , status;
pthread_t threads[1];
printf("Starting Threads...\n");
pthread_create(&threads[0], NULL, sendData, NULL);
rc = pthread_join(threads[0], (void **) &status);
}
Heres the source of the reader
#define pipe "/tmp/testPipe"
char dataString[50000];
using namespace std;
char *getSproutItem();
void* readItem(void *thread_arg)
{
while(1)
{
x++;
char *s = getSproutItem();
if(s != NULL)
{
cout << "READ IN: " << s << endl;
}
}
}
ssize_t r_read(int fd, char *buf, size_t size) {
ssize_t retval;
while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ;
return retval;
}
char * getSproutItem()
{
cout << "Getting item" << endl;
char stringSize[4];
bzero(stringSize, sizeof(stringSize));
int fd = open(pipe,O_RDONLY);
cout << "Reading" << endl;
int numread = r_read(fd,stringSize, sizeof(stringSize));
if(errno == EPIPE)
{
signal(SIGPIPE,SIG_IGN);
}
cout << "Read Complete" << endl;
if(numread > 1)
{
stringSize[numread] = '\0';
int length = atoi(stringSize);
char recievedString[length];
bzero(recievedString, sizeof(recievedString));
int numread1 = r_read(fd, recievedString, sizeof(recievedString));
if(errno == EPIPE)
{
signal(SIGPIPE,SIG_IGN);
}
if(numread1 > 1)
{
recievedString[numread1] = '\0';
cout << "DATA RECIEVED: " << recievedString << endl;
bzero(dataString, sizeof(dataString));
strncpy(dataString, recievedString, strlen(recievedString));
strncat(dataString, "\0", strlen("\0"));
close(fd);
return dataString;
}
else
{
return NULL;
}
}
else
{
return NULL;
}
close(fd);
}
int main(int argc, char *argv[])
{
int rc, i , status;
pthread_t threads[1];
printf("Starting Threads...\n");
pthread_create(&threads[0], NULL, readItem, NULL);
rc = pthread_join(threads[0], (void **) &status);
}
You are definitely using signals the wrong way. Threads are completely unnecessary here - at least in the code provided. String calculations are just weird. Get this book and do not touch the keyboard until you finished reading :)
The general method used to send data through named pipes is to tack on a header with the length of the payload. Then you read(fd, header_len); read(rd, data_len); Note the latter read() will need to be done in a loop until data_len is read or eof. Note also if you've multiple writers to a named pipe then the writes are atomic (as long as a reasonable size) I.E. multiple writers will not case partial messages in the kernel buffers.
It's difficult to say what is going on here. Maybe you are getting an error returned from one of your system calls? Are you sure that you are successfully sending all of the data?
You also appear to have some invalid code here:
int length = atoi(stringSize);
char recievedString[length];
This is a syntax error, since you cannot create an array on the stack using a non-constanct expression for the size. Maybe you are using different code in your real version?
Do you need to read the data in a loop? Sometimes a function will return a portion of the available data and require you to call it repeatedly until all of the data is gone.
Some system calls in Unix can also return EAGAIN if the system call is interrupted - you are not handling this case by the looks of things.
You are possibly getting bitten by POSIX thread signal handling semantics in your reader main thread.
The POSIX standard allows for a POSIX thread to receive the signal, not necessarily the thread you expect. Block signals where not wanted.
signal(SIG_PIPE,SIG_IGN) is your friend. Add one to reader main.
POSIX thread handling semantics, putting the POS into POSIX. ( but it does make it easier to implement POSIX threads.)
Examine the pipe in /tmp with ls ? is it not empty ?