Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPI and FPVA fixes #25

Merged
merged 13 commits into from
Mar 23, 2022
Merged
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@
file is also used by Makefile, I don't put `pwd` in it.
- DYNLINK: true for building shared library for agent, otherwise for building
static library
3. Run `make spi` to build injector and libagent.so.
4. Run `make test_agent` to build example user agents
- PLATFORM: set to x86_64-unknown-linux2.4 or i386-unknown-linux2.4
3. Run `make spi` in directory x86_64-unknown-linux2.4/ or i386-unknown-linux2.4/ to build injector and libagent.so.
4. Run `make test_agent` in one of the above directories to build example user agents
5. For more make options, see [Make Arguments](#make-arguments)

## How to Run
1. Export Runtime environment variables, see Environment Variable section for [detail](#environment-variables):
1. `SP_DIR`
2. `PLATFORM`
3. `SP_AGENT_DIR`
4. `PLATFORM`
2. Make sure that your system does not block non-child ptrace
- To temporarily disable this measure (until a reboot), execute the following command:
`echo 0 > /proc/sys/kernel/yama/ptrace_scope`
Expand All @@ -40,7 +42,7 @@
1. To use the environment variable LD_PRELOAD when starting the user process.
Ex: `LD_PRELOAD=$SP_DIR/PLATFORM/test_agent/print_test_agent.so [EXECUTABLE]`
1. To use the injector to force a running process to load agent library, note that injector has two modes, pid injection and port injection
Ex: `$SP_DIR/PLATFORM/injector.exe pid [PID]` or `$SP_DIR/PLATFORM/injector.exe port [PORT NUMBER]`
Ex: `$SP_DIR/$PLATFORM/injector.exe pid [PID]` or `$SP_DIR/$PLATFORM/injector.exe port [PORT NUMBER]`
### Interprocess Propel
- Local Machine
- Interprocess propelling relies on the following environment variables: `SP_DIR`, `PLATFORM`, `SP_AGENT_DIR`
Expand Down Expand Up @@ -90,4 +92,4 @@
- make clean_test: clean test stuffs
- make clean: only clean core self-propelled stuffs, excluding dependency
- make clean_all: clean everything, including dependency
- make clean_objs: clean core self-propelled objs
- make clean_objs: clean core self-propelled objs
2 changes: 1 addition & 1 deletion common.flag.mk
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ COMMON_LDFLAGS += -lboost_system

COMMON_LDFLAGS += -lpthread -lthread_db


COMMON_LDFLAGS += -ltbbmalloc


#COMMON_LDFLAGS += -L$(LIBDWARF_LIB)
Expand Down
44 changes: 24 additions & 20 deletions src/agent/agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
FILE* g_debug_fp;
FILE* g_error_fp;
FILE* g_output_fp;
bool debugTypeEnabled [numDebugTypes] = {getenv("SP_DEBUG_INJECTOR"), getenv("SP_DEBUG_COMMON"), getenv("SP_DEBUG_PATCHAPI"), getenv("SP_DEBUG_IPC"), getenv("SP_DEBUG_WORKER"), getenv("SP_DEBUG_SIGTRAP"), getenv("SP_DEBUG_AGENT"), true};
bool sp_debug = getenv("SP_DEBUG");
bool sp_fdebug = getenv("SP_FDEBUG");

namespace sp {

Expand Down Expand Up @@ -197,12 +200,13 @@ namespace sp {

void
SpAgent::Go() {
sp_debug("==== Start Self-propelled instrumentation @ Process %d ====",

sp_debug_agent("==== Start Self-propelled instrumentation @ Process %d ====",
getpid());

// XXX: ignore bash/lsof/Injector for now ...
if (sp::IsIllegalProgram()) {
sp_debug("ILLEGAL EXE - avoid instrumenting %s", GetExeName().c_str());
sp_debug_agent("ILLEGAL EXE - avoid instrumenting %s", GetExeName().c_str());
return;
}

Expand Down Expand Up @@ -235,47 +239,47 @@ namespace sp {

// Sanity check. If not user-provided configuration, use default ones
if (!init_event_) {
sp_debug("INIT EVENT - Use default event");
sp_debug_agent("INIT EVENT - Use default event");
init_event_ = SyncEvent::Create();
}
if (!fini_event_) {
sp_debug("FINI EVENT - Use default event");
sp_debug_agent("FINI EVENT - Use default event");
fini_event_ = SpEvent::Create();
}
if (init_entry_.size() == 0) {
sp_debug("ENTRY_PAYLOAD - Use default payload entry calls");
sp_debug_agent("ENTRY_PAYLOAD - Use default payload entry calls");
init_entry_ = "default_entry";
}
if (init_exit_.size() == 0) {
sp_debug("EXIT_PAYLOAD - No payload exit calls");
sp_debug_agent("EXIT_PAYLOAD - No payload exit calls");
init_exit_ = "";
}
if (!parser_) {
sp_debug("PARSER - Use default parser");
sp_debug_agent("PARSER - Use default parser");
parser_ = SpParser::Create();
}
if (!init_propeller_) {
sp_debug("PROPELLER - Use default propeller");
sp_debug_agent("PROPELLER - Use default propeller");
init_propeller_ = SpPropeller::Create();
}

if (directcall_only_) {
sp_debug("DIRECT CALL ONLY - only instrument direct calls,"
sp_debug_agent("DIRECT CALL ONLY - only instrument direct calls,"
" ignoring indirect calls");
} else {
sp_debug("DIRECT/INDIRECT CALL - instrument both direct and"
sp_debug_agent("DIRECT/INDIRECT CALL - instrument both direct and"
" indirect calls");
}
if (allow_ipc_) {
sp_debug("MULTI PROCESS - support multiprocess instrumentation");
sp_debug_agent("MULTI PROCESS - support multiprocess instrumentation");
} else {
sp_debug("SINGLE PROCESS - only support single-process "
sp_debug_agent("SINGLE PROCESS - only support single-process "
"instrumentation");
}
if (trap_only_) {
sp_debug("TRAP ONLY - Only use trap-based instrumentation");
sp_debug_agent("TRAP ONLY - Only use trap-based instrumentation");
} else {
sp_debug("JUMP + TRAP - Use jump and trap for instrumentation");
sp_debug_agent("JUMP + TRAP - Use jump and trap for instrumentation");
}


Expand All @@ -292,7 +296,7 @@ namespace sp {

// We use default event, which does nothing on initial instrumentation
if (parse_only_) {
sp_debug("PARSE ONLY - exit after parsing, without instrumentation");
sp_debug_agent("PARSE ONLY - exit after parsing, without instrumentation");
sp::SpEvent::ptr init_event = sp::SpEvent::Create();
init_event_ = init_event;
// return;
Expand All @@ -312,7 +316,7 @@ namespace sp {


// Copy agent's variables to context
sp_debug("Copy agent's variables to context");
sp_debug_agent("Copy agent's variables to context");
g_context->SetInitPropeller(init_propeller_);
g_context->SetParser(parser_);
g_context->SetInitEntryName(init_entry_);
Expand Down Expand Up @@ -343,7 +347,7 @@ namespace sp {
}

// Always use wrapper functions for payload entry and exit
sp_debug("ALLOW IPC OR MULTITHREADED OR HANDLE_DLOPEN");
sp_debug_agent("ALLOW IPC OR MULTITHREADED OR HANDLE_DLOPEN");
void* wrapper_entry =
(void*)g_parser->GetFuncAddrFromName("wrapper_entry");
assert(wrapper_entry);
Expand All @@ -355,9 +359,9 @@ namespace sp {

// Register Events for initial instrumentation
init_event_->RegisterEvent();
sp_debug("init registered");
sp_debug_agent("init registered");
fini_event_->RegisterEvent();
sp_debug("fini registered");
sp_debug_agent("fini registered");

std::string exit_function_payload_str("toggle_off_instrumentation_entry");
void* exit_function_payload = (void*)g_parser->GetFuncAddrFromName(exit_function_payload_str);
Expand All @@ -381,7 +385,7 @@ namespace sp {
i != found_exit_funcs.end(); i++) {
if (*i == NULL) continue;
SpFunction* f = *i;
sp_debug("Pre-instrumenting exit function: %s", f->name().c_str());
sp_debug_agent("Pre-instrumenting exit function: %s", f->name().c_str());
g_context->init_propeller()->go(f,
exit_function_payload,
g_context->init_exit());
Expand Down
4 changes: 2 additions & 2 deletions src/agent/agent_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ TEST_F(AgentTest, default_setting) {
EXPECT_TRUE(agent->init_propeller() != NULL);
EXPECT_STREQ(agent->init_entry().c_str(), "default_entry");
EXPECT_TRUE(agent->init_exit().size() == 0);
EXPECT_TRUE(agent->libraries_to_instrument().size() == 0);
//EXPECT_TRUE(agent->libraries_to_instrument().size() == 0);
EXPECT_FALSE(agent->IsParseOnlyEnabled());
EXPECT_FALSE(agent->IsDirectcallOnlyEnabled());
EXPECT_FALSE(agent->IsTrapOnlyEnabled());
Expand Down Expand Up @@ -71,7 +71,7 @@ TEST_F(AgentTest, customized_setting) {

sp::StringSet libs_to_inst;
libs_to_inst.insert("libtest1.so");
agent->SetLibrariesToInstrument(libs_to_inst);
//agent->SetLibrariesToInstrument(libs_to_inst);

sp::StringSet funcs_not_to_inst;
funcs_not_to_inst.insert("std::");
Expand Down
16 changes: 8 additions & 8 deletions src/agent/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ namespace sp {
/*
void* buffer[100];
int num = backtrace(buffer, 100);
sp_debug("%d traces", num);
sp_debug_agent("%d traces", num);
char** syms = backtrace_symbols(buffer, num);
for (int i = 0; i < num; i++) {
sp_debug("%lx - %s", *(unsigned long*)buffer[i], syms[i]);
sp_debug_agent("%p - %s", *buffer[i], syms[i]);
}
return;
*/
Expand All @@ -95,14 +95,14 @@ namespace sp {
SpFunction* func = parser_->FindFunction(pc);
if (func) sp_print("%s", func->name().c_str());

sp_debug("GET FRAME - pc: %lx, sp: %lx, bp: %lx", pc, sp, bp);
sp_debug_agent("GET FRAME - pc: %lx, sp: %lx, bp: %lx", pc, sp, bp);
sk::Frame* f = sk::Frame::newFrame(pc, sp, bp, walker_);
sp_debug("constructed frame");
sp_debug_agent("constructed frame");
assert(walker_);

//Get the total number of calls in stack using StackWalkerAPI
walker_->walkStackFromFrame(stackwalk_, *f);
sp_debug("WALKED STACK - %ld function calls found",
sp_debug_agent("WALKED STACK - %ld function calls found",
(long)stackwalk_.size());

for (unsigned i=0; i<stackwalk_.size(); i++) {
Expand All @@ -121,12 +121,12 @@ namespace sp {
// Step 1: if the function can be resolved
SpFunction* func = parser_->FindFunction(s.c_str());
if (!func) {
sp_debug("SKIPPED - Function %s cannot be resolved", s.c_str());
sp_debug_agent("SKIPPED - Function %s cannot be resolved", s.c_str());
continue;
}

// Step 2: add this function
sp_debug("FOUND - Function %s is in the call stack", s.c_str());
sp_debug_agent("FOUND - Function %s is in the call stack", s.c_str());
call_stack->insert(func);
*/
}
Expand All @@ -140,7 +140,7 @@ namespace sp {
stackwalk_[i].getName(func);
if(IsRecvLikeFunction(func.c_str())) {
sk::location_t location =stackwalk_[i+1].getRALocation();
sp_debug("Function %s Return Address on the stack = %lx",func.c_str(),location.val.addr);
sp_debug_agent("Function %s Return Address on the stack = %lx",func.c_str(),location.val.addr);
return (dt::Address) stackwalk_[i+1].getRA();
}
}
Expand Down
28 changes: 18 additions & 10 deletions src/agent/event.cc
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,28 @@ namespace sp {
than zero, then the agent is injected */
FuncSet call_stack;
g_context->GetCallStack(&call_stack);
sp_debug("CALLSTACK - %lu calls in the call stack",
sp_debug_agent("CALLSTACK - %lu calls in the call stack",
(unsigned long)call_stack.size());

if (call_stack.size() <= 0) {
sp_debug("PRELOAD - preload agent.so, and instrument main()");

SpFunction* f = g_parser->FindFunction("main");
sp_debug_agent("PRELOAD - preload agent.so, and instrument main()");
sp_debug_agent(GetExeName().c_str());

FuncSet found_funcs;
SpFunction* f = NULL;
found_funcs = g_parser->FindFunctionByMangledName("main");
for (auto i: found_funcs) {
if (FUNC_CAST(i)->GetObject()->name() == sp::GetExeObjName())
f = FUNC_CAST(i);
}
//f = g_parser->FindFunction("main");
if (f) {
g_context->init_propeller()->go(f,
g_context->init_entry(),
g_context->init_exit());

} else {
sp_debug("FAIL PRELOAD - try injection ...");
sp_debug_agent("FAIL PRELOAD - try injection ...");
fail_preload = true;
}
} // LD_PRELOAD mode
Expand All @@ -138,7 +146,7 @@ namespace sp {
for (FuncSet::iterator i = call_stack.begin();
i != call_stack.end(); i++) {
SpFunction* f = *i;
sp_debug("Call stck function %s",f->name().c_str());
sp_debug_agent("Call stck function %s",f->name().c_str());
g_context->init_propeller()->go(f,
g_context->init_entry(),
g_context->init_exit());
Expand All @@ -147,7 +155,7 @@ namespace sp {
break;
}
if (IsRecvLikeFunction(f->name())) {
sp_debug("Recv like function on the stack");
sp_debug_agent("Recv like function on the stack");
//Modify the PC to start at a new location
g_context->init_propeller()->ModifyPC(f,g_context->init_exit());
}
Expand Down Expand Up @@ -183,7 +191,7 @@ namespace sp {
for (FuncSet::iterator i = funcs_.begin();
i != funcs_.end(); i++) {
SpFunction* f = *i;
sp_debug("PRE-INST FUNC - %s", f->name().c_str());
sp_debug_agent("PRE-INST FUNC - %s", f->name().c_str());
g_context->init_propeller()->go(f,
g_context->init_entry(),
g_context->init_exit());
Expand Down Expand Up @@ -217,12 +225,12 @@ namespace sp {
assert(obj);

if (strcmp(sp_filename(obj->name().c_str()), "libagent.so") == 0) {
sp_debug("SKIP - lib %s", sp_filename(obj->name().c_str()));
sp_debug_agent("SKIP - lib %s", sp_filename(obj->name().c_str()));
continue;
}

if (!g_parser->CanInstrumentLib(sp_filename(obj->name().c_str()))) {
sp_debug("SKIP - lib %s", sp_filename(obj->name().c_str()));
sp_debug_agent("SKIP - lib %s", sp_filename(obj->name().c_str()));
continue;
}
// sp_print("HANDLING - lib %s", sp_filename(obj->name().c_str()));
Expand Down
Loading