Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 42 additions & 20 deletions src/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1200,18 +1200,28 @@ static void do_trace(pid_t tracee) {
if (child_waited == -1)
break;

// Signal to forward when we resume the tracee. Stays 0 for syscall
// stops and ptrace events; gets set to the actual signal number for
// genuine signal-delivery stops, so the streamer's signal-driven
// logic (HiSilicon SDK uses realtime signals heavily) still works
// under trace.
int sig_to_inject = 0;

if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
if (((status >> 16) & 0xffff) == PTRACE_EVENT_CLONE) {
int event = (status >> 16) & 0xffff;
// CLONE/FORK/VFORK all create a new tracee that needs the same
// bookkeeping: pull its pid from the kernel, look up the parent's
// process_t, copy its fd state, register the new tracee.
if (event == PTRACE_EVENT_CLONE || event == PTRACE_EVENT_FORK ||
event == PTRACE_EVENT_VFORK) {
pid_t new_child;
if (ptrace(PTRACE_GETEVENTMSG, child_waited, 0, &new_child) !=
-1) {
pid_t ppid = -1;
if (!ht_contains(&pids, &new_child)) {
ppid = get_process_parent_id(new_child);
// TODO: review
if (ppid == tracer)
ppid = tracee;
//
process_t *thread = &(process_t){.pid = new_child};
process_t *parent = ht_lookup(&pids, &ppid);
if (parent) {
Expand Down Expand Up @@ -1239,34 +1249,46 @@ static void do_trace(pid_t tracee) {
printf("\nchild %d killed by signal %d\n", child_waited,
WTERMSIG(status));
process_t *proc = ht_lookup(&pids, &child_waited);
if (proc == NULL) {
fprintf(stderr, "Cannot lookup PID %d\n", child_waited);
break;
if (proc != NULL) {
free_fds(proc);
ht_erase(&pids, &child_waited);
}
free_fds(proc);
ht_erase(&pids, &child_waited);

if (ht_is_empty(&pids))
break;
continue; // don't try to restart a dead pid
} else if (WIFSTOPPED(status)) {
int stopCode = WSTOPSIG(status);
if (stopCode == SIGTRAP) {
process_t *proc = ht_lookup(&pids, &child_waited);
if (proc == NULL) {
printf("BAD lookup for %d\n", child_waited);
break;
}

if (!proc->syscall_num) {
enter_syscall(proc);
} else {
exit_syscall(proc);
proc->syscall_num = 0;
if (proc != NULL) {
if (!proc->syscall_num) {
enter_syscall(proc);
} else {
exit_syscall(proc);
proc->syscall_num = 0;
}
}
// If proc is NULL here it means a child was created with
// a fork-family event we didn't observe yet (TRACEFORK/
// TRACEVFORK race). Continue tracing rather than killing
// the whole loop - it will get added on its first observed
// event.
} else if (stopCode == SIGSTOP || stopCode == SIGTSTP ||
stopCode == SIGTTIN || stopCode == SIGTTOU) {
// Group-stop / post-clone init-stop. The kernel SIGSTOPs a
// newly cloned tracee as part of TRACECLONE bookkeeping;
// forwarding it back would re-stop the child and we'd
// never see its syscalls (this exact bug surfaced as
// "empty trace" on hi3518ev200 + libsns_jxf22.so where
// sensor I/O happens in a clone'd thread). Suppress.
} else {
// Real signal delivery - forward to the tracee.
sig_to_inject = stopCode;
}
}

ptrace(PTRACE_SYSCALL, child_waited, 1, NULL);
ptrace(PTRACE_SYSCALL, child_waited, 0,
(void *)(intptr_t)sig_to_inject);
}
}

Expand Down
92 changes: 92 additions & 0 deletions tools/sns_init_probe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Tiny wrapper that loads a libsns_*.so directly and calls its sensor
// init function, without pulling in the rest of the streamer. Lets us
// exercise the .so's I2C path under ipctool trace in isolation.
//
// Build for ARM with the OpenIPC toolchain:
// arm-openipc-linux-musleabi-gcc -O2 -static \
// tools/sns_init_probe.c -ldl -lpthread \
// -o sns_init_probe
//
// Run on the camera (after killing the streamer so the I2C bus is free):
// killall majestic
// sns_init_probe /usr/lib/sensors/libsns_jxf22.so sensor_linear_1080p30_init
//
// Or under trace:
// ipctool trace --output=cap.log sns_init_probe /usr/lib/sensors/libsns_jxf22.so sensor_init
//
// We accept either symbol name; if neither is exported we fall back to
// sensor_init (the SDK glue most drivers expose).
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int (*init_fn_int)(int);
typedef void (*init_fn_void)(int);

int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr,
"usage: %s <path to libsns_xxx.so> [symbol]\n"
" default symbol search: sensor_linear_1080p30_init,\n"
" sensor_init, sensor_i2c_init\n",
argv[0]);
return 2;
}

const char *so = argv[1];
void *h = dlopen(so, RTLD_NOW);
if (!h) {
fprintf(stderr, "dlopen(%s) failed: %s\n", so, dlerror());
return 1;
}

const char *try_syms[4];
int nsyms = 0;
if (argc >= 3) {
try_syms[nsyms++] = argv[2];
} else {
try_syms[nsyms++] = "sensor_linear_1080p30_init";
try_syms[nsyms++] = "sensor_init";
try_syms[nsyms++] = "sensor_i2c_init";
}

void *fn = NULL;
const char *sym = NULL;
for (int i = 0; i < nsyms; i++) {
dlerror();
fn = dlsym(h, try_syms[i]);
if (fn) {
sym = try_syms[i];
break;
}
}
if (!fn) {
fprintf(stderr, "no init symbol found in %s\n", so);
return 1;
}

fprintf(stderr, "[probe] %s @ %p — calling\n", sym, fn);

// First always do sensor_i2c_init to set up the bus, in case the user
// asked for sensor_linear_1080p30_init directly (which doesn't open
// the i2c device).
void *i2c_init = dlsym(h, "sensor_i2c_init");
if (i2c_init && i2c_init != fn) {
((init_fn_void)i2c_init)(0);
}

// Some symbols return int, some void. Calling void as int is harmless
// on ARM EABI (return value just goes unused).
int ret = ((init_fn_int)fn)(0);
fprintf(stderr, "[probe] %s returned %d\n", sym, ret);

void *i2c_exit = dlsym(h, "sensor_i2c_exit");
if (i2c_exit) {
((init_fn_void)i2c_exit)(0);
}

dlclose(h);
return 0;
}
Loading