blob: 5612b474344589e930069c465a246689ded68352 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file declares the Call Trace "Client" class, which is responsible
// for providing all of the Call Trace DLL functionality.
#ifndef SYZYGY_AGENT_CALL_TRACE_CLIENT_RPC_H_
#define SYZYGY_AGENT_CALL_TRACE_CLIENT_RPC_H_
#include <map>
#include <utility>
#include <vector>
#include "base/synchronization/lock.h"
#include "base/threading/thread_local.h"
#include "syzygy/agent/common/entry_frame.h"
#include "syzygy/trace/client/rpc_session.h"
// Assembly instrumentation stubs to handle function entry and exit. These
// respectively invoke Client::FunctionEntryHook, Client::DllMainEntryHook,
// Client::FunctionExitHook and Client::DllMainExitHook.
extern "C" void _cdecl _indirect_penter();
extern "C" void _cdecl _indirect_penter_dllmain();
namespace agent {
namespace client {
class Client {
public:
Client();
~Client();
static Client* Instance();
BOOL WINAPI DllMain(HMODULE module, DWORD reason, LPVOID reserved);
protected:
typedef agent::EntryFrame EntryFrame;
friend void _indirect_penter();
friend void _indirect_penter_dll_main();
// Invoked by _indirect_penter_dllmain on entry to a DLL's entry point.
//
// This function will initialize a call trace session if none currently
// exists and will transmit module information to the call trace service.
// It will then log the entry into the DLL's entry point.
//
// @param entry_frame The entry frame for the module entry point
// @param function The module entry point
static void WINAPI DllMainEntryHook(EntryFrame* entry_frame,
FuncAddr function);
// Invoked by _indirect_penter on function entry.
//
// @param entry_frame The entry frame for the called function.
// @param function The called function.
static void WINAPI FunctionEntryHook(EntryFrame* entry_frame,
FuncAddr function);
private:
// We keep a structure of this type for each thread.
class ThreadLocalData;
// The functions we use to manage the thread local data.
ThreadLocalData* GetThreadData();
ThreadLocalData* GetOrAllocateThreadData();
void FreeThreadData(ThreadLocalData* data);
void FreeThreadData();
// DllMain Handler functions. We only handle detach events in DllMain, the
// attachment events are deferred to the first use of an event hook. This
// is an attempt to avoid running afoul of the module loader lock and/or
// load order problems. Further, we don't need/want to handle attachment
// events for non-instrumented modules, anyway.
void OnClientProcessDetach();
void OnClientThreadDetach();
// This function will initialize a call trace session if none currently
// exists and the event is DLL_PROCESS_ATTACH. It will then transmit a
// module event record to the call trace service.
//
// @param data the thread local data describing this threads call trace
// log buffer.
// @param entry_frame the entry frame for the module entry point
// @param function the module entry point
void LogEvent_ModuleEvent(ThreadLocalData *data,
HMODULE module,
DWORD reason);
// Called by FunctionEntryHook and DllMainEntryHook.
//
// This function will log the entry into the given function.
//
// If module is not NULL and reason is either DLL_THREAD_ATTACH or
// DLL_PROCESS_ATTACH, the function first logs the module event before
// logging the function entry.
//
// @param entry_frame The entry frame for the called function.
// @param function The called function.
// @param module NULL unless the entry denotes an instrumented dll's entry
// point being called.
// @param reason If module is NULL this is ignored; otherwise, it must be
// DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, DLL_THREAD_ATTACH or
// DLL_THREAD_DETACH.
void LogEvent_FunctionEntry(EntryFrame* entry_frame,
FuncAddr function,
HMODULE module,
DWORD reason);
// The initialization lock.
base::Lock init_lock_;
// Our RPC session state.
trace::client::RpcSession session_;
// This points to our per-thread state.
mutable base::ThreadLocalPointer<ThreadLocalData> tls_;
};
} // namespace client
} // namespace agent
#endif // SYZYGY_AGENT_CALL_TRACE_CLIENT_RPC_H_