1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // Declares utility functions used by the call trace client and its unit
16 : // tests.
17 :
18 : #ifndef SYZYGY_TRACE_CLIENT_CLIENT_UTILS_H_
19 : #define SYZYGY_TRACE_CLIENT_CLIENT_UTILS_H_
20 :
21 : #include "base/files/file_path.h"
22 : #include "syzygy/trace/protocol/call_trace_defs.h"
23 : #include "syzygy/trace/rpc/call_trace_rpc.h"
24 :
25 : namespace trace {
26 : namespace client {
27 :
28 : // Forward declaration.
29 : class RpcSession;
30 :
31 : // This structure captures everything that a thread needs to know about
32 : // its current call trace buffer, which corresponds to a call trace segment
33 : // on disk. It holds the buffer information given by the call trace service,
34 : // the memory locations this buffer refers to in the client process, and a
35 : // pointer to the segment header within the buffer so that the segment can
36 : // be consistently maintained.
37 : class TraceFileSegment {
38 : public:
39 : TraceFileSegment();
40 :
41 : // @returns true if there's enough space left in the given segment to write
42 : // num_bytes of raw data.
43 : bool CanAllocateRaw(size_t num_bytes) const;
44 :
45 : // @returns true if there's enough space left in the given segment to write
46 : // a prefixed record of length num_bytes.
47 : bool CanAllocate(size_t num_bytes) const;
48 :
49 : // Writes the segment header at the top of a segment, updating the bytes
50 : // consumed and initializing the segment header structures.
51 : void WriteSegmentHeader(SessionHandle session_handle);
52 :
53 : // Allocate a variable length trace record. Typically this is used when
54 : // the record has a fixed set of fields followed by some variable size
55 : // blob or string. The size given must exceed the size of the records
56 : // fixed fields.
57 : //
58 : // @returns a pointer to the allocated record, such that you can populate
59 : // its values.
60 : template<typename RecordType>
61 E : inline RecordType* AllocateTraceRecord(size_t size) {
62 E : DCHECK(size >= sizeof(RecordType));
63 : return reinterpret_cast<RecordType*>(
64 E : AllocateTraceRecordImpl(RecordType::kTypeId, size));
65 E : }
66 :
67 : // Allocate a fixed length trace record.
68 : //
69 : // @returns a pointer to the allocated record, such that you can populate
70 : // its values.
71 : template<typename RecordType>
72 E : inline RecordType* AllocateTraceRecord() {
73 E : return AllocateTraceRecord<RecordType>(sizeof(RecordType));
74 E : }
75 :
76 : // TODO(siggi): Make this private.
77 : public:
78 : // Internal implementation of the trace record allocation function.
79 : void* AllocateTraceRecordImpl(int record_type,
80 : size_t record_size);
81 :
82 : // The structure used to communicate buffer information between the
83 : // client and call trace service.
84 : CallTraceBuffer buffer_info;
85 :
86 : // Points to the segment header within the call trace buffer. This
87 : // can be used to update the segment_length after appending new
88 : // data to the buffer.
89 : TraceFileSegmentHeader* header;
90 :
91 : // The lower bound of the call trace buffer in the client process.
92 : uint8* base_ptr;
93 :
94 : // The next memory location at which the client should write call
95 : // trace data.
96 : uint8* write_ptr;
97 :
98 : // The upper bound of the call trace buffer in the client process.
99 : uint8* end_ptr;
100 : };
101 :
102 : // Helper function to transform a DllMain reason to a call trace event type.
103 : int ReasonToEventType(DWORD reason);
104 :
105 : // Helper function to get pointer to the prefix for any record
106 : // in a trace file segment.
107 : RecordPrefix* GetRecordPrefix(void *record);
108 :
109 : // Given an address in memory returns a pointer to the base address of the
110 : // loaded module in which it lies. Logs verbosely on failure.
111 : // @param address_in_module an address in the image.
112 : // @param module_base will receive a pointer to the base address of the image.
113 : // @returns true on success, false otherwise.
114 : bool GetModuleBaseAddress(void* address_in_module, void** module_base);
115 :
116 : // Determines the full path associated with a given module in memory. This is
117 : // replicating functionality from base::PathService, but it uses
118 : // GetModuleFileName which grabs the loader lock. This can cause us issues
119 : // thus we use GetMappedFileName instead.
120 : // @param module_base the base address of the module to be queried.
121 : // @param module_path will receive the path of the module, upon success.
122 : // @returns true on success, false otherwise.
123 : bool GetModulePath(void* module_base, base::FilePath* module_path);
124 :
125 : // Given the path to a module, determines the RPC instance ID to be used for
126 : // it. This works by looking at the SYZYGY_RPC_INSTANCE_ID environment variable.
127 : // This environment variable contains a semi-colon separated list of instance
128 : // IDs, where each entry may consist of a comma separated module path and
129 : // instance ID pair. The first semi-colon delimited entry that is a singleton
130 : // is used as the instance ID if no path matches are found. Exact path matches
131 : // have higher priority over basename-only path matches. If no match is found
132 : // and no default ID exists (or the environment variable is not specified), then
133 : // the returned instance ID is empty.
134 : //
135 : // For example, consider the following environment variable:
136 : //
137 : // SYZYGY_RPC_INSTANCE_ID="1;foo.dll,2;C:\dll\foo.dll,3"
138 : //
139 : // If called with the path "C:\src\foo.dll" then the returned instance ID will
140 : // be "2". If called with the path "C:\dll\foo.dll" the returned instance ID
141 : // will be "3". If called with "C:\bar.dll" the returned instance ID will be
142 : // "1".
143 : //
144 : // @param module_path the path to the module for which we wish to find an
145 : // instance ID. If it is not absolute it will be made so using the current
146 : // working directory.
147 : // @returns the instance ID.
148 : std::string GetInstanceIdForModule(const base::FilePath& module_path);
149 :
150 : // Encapsulates calls to GetModuleBaseAddress, GetModulePath and
151 : // GetInstanceIdForModule.
152 : // @returns the instance ID for the module in which this function is found.
153 : std::string GetInstanceIdForThisModule();
154 :
155 : // Given the path to a module, determines whether or not an RPC connection
156 : // is mandatory for it. This works by looking at the
157 : // SYZYGY_RPC_SESSION_MANDATORY environment variable. This consists of a
158 : // semi-colon separated list of paths and values, similar to
159 : // SYZYGY_RPC_INSTANCE_ID as described in GetInstanceIdForModule. Rather than
160 : // an ID, the value is an integer where 0 = False and non-zero = True.
161 : // If the path matching process returns a non-zero value then failure to create
162 : // an RPC session will cause the instrumented process to terminate with an
163 : // error.
164 : //
165 : // @param module_path the path to the module for which we wish to determine if
166 : // and RPC session is mandatory.
167 : // @returns true if the session is mandatory, false otherwise.
168 : bool IsRpcSessionMandatory(const base::FilePath& module_path);
169 :
170 : // Encapsulates calls to GetModuleBaseAddress, GetModulePath and
171 : // IsRpcSessionMandatory.
172 : // @returns true if an RPC session is mandatory for the module in which this
173 : // function is found.
174 : bool IsRpcSessionMandatoryForThisModule();
175 :
176 : // Initializes an RPC session, automatically getting the instance ID and
177 : // determining if the session is mandatory. If the session is mandatory and it
178 : // is unable to be connected this will raise an exception and cause the process
179 : // to abort.
180 : // @param rpc_session the session to initialize.
181 : // @param segment will receive the first allocated segment upon successful
182 : // initialization.
183 : // @returns true if everything went well, false if anything went wrong and the
184 : // session is not mandatory.
185 : bool InitializeRpcSession(RpcSession* rpc_session, TraceFileSegment* segment);
186 :
187 : } // namespace trace::client
188 : } // namespace trace
189 :
190 : #endif // SYZYGY_TRACE_CLIENT_CLIENT_UTILS_H_
|