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