Skip to content

Commit 093009b

Browse files
committed
Enhance the Remote / RemoteAST libraries with an error mechanism.
Nothing is producing meaningful errors yet, however.
1 parent 2e3662d commit 093009b

File tree

6 files changed

+536
-43
lines changed

6 files changed

+536
-43
lines changed

include/swift/Remote/Failure.h

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
//===--- Failure.h - Failure to access remote memory ------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file provides a simple diagnostics library for the various
14+
// operations for working with a remote process.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_REMOTE_FAILURE_H
19+
#define SWIFT_REMOTE_FAILURE_H
20+
21+
#include "swift/Remote/RemoteAddress.h"
22+
23+
#include "llvm/Support/Compiler.h"
24+
#include <string>
25+
#include <cstring>
26+
#include <type_traits>
27+
28+
namespace swift {
29+
namespace remote {
30+
31+
class Failure {
32+
public:
33+
/// An enum which unifies all of the failure kinds into a single namespace.
34+
/// This is how kinds are stored internally.
35+
enum class Kind {
36+
#define FAILURE(KIND, TEXT, ARGTYS) KIND,
37+
#include "swift/Remote/FailureKinds.def"
38+
};
39+
40+
/// A bunch of enums for all the different kinds of failure.
41+
/// Users should construct a Failure by passing Failure::KIND instead
42+
/// of Failure::Kind::KIND.
43+
#define FAILURE(KIND, TEXT, ARGTYS) \
44+
enum KIND##_t { KIND = unsigned(Kind::KIND) };
45+
#include "swift/Remote/FailureKinds.def"
46+
47+
private:
48+
// A whole lot of template machinery to validate that the right argument
49+
// types were passed:
50+
51+
// A sequence of types.
52+
template <class... Tys> struct TypeBundle {};
53+
54+
// A way of turning (X, Y, Z) into a TypeBundle:
55+
// typename TypeBundleForFunctionTypeParameters<void ARGS>::types
56+
// Partially specialized at the end of this file.
57+
template <class FnTy> struct TypeBundleForFunctionTypeParameters;
58+
59+
// A way of getting the expected TypeBundle of (nonce) argument types
60+
// for a particular failure kind:
61+
// typename ArgTypesForFailureKind<KindTy>::types
62+
// Explicitly specialized for each kind type at the end of this file.
63+
template <class KindTy> struct ArgTypesForFailureKind;
64+
65+
// Nonce expected argument types.
66+
enum ArgType_String {};
67+
enum ArgType_Address {};
68+
69+
// A predicate that decides whether the given argument type satisfies
70+
// the given nonce expected argument type.
71+
template <class Expected, class Actual> struct IsAcceptableArgType {
72+
static constexpr bool value = false;
73+
};
74+
75+
template <class... Ts>
76+
static void validateFailureArgsRecursive(TypeBundle<Ts...> expected,
77+
TypeBundle<> actual) {
78+
static_assert(std::is_same<decltype(expected), decltype(actual)>::value,
79+
"too few arguments to diagnostic");
80+
}
81+
82+
template <class Expected, class... RestOfExpected,
83+
class Actual, class... RestOfActual>
84+
static void validateFailureArgsRecursive(
85+
TypeBundle<Expected, RestOfExpected...> expected,
86+
TypeBundle<Actual, RestOfActual...> actual) {
87+
using SimplifiedActual = typename std::decay<Actual>::type;
88+
static_assert(IsAcceptableArgType<Expected, SimplifiedActual>::value,
89+
"argument does no match");
90+
validateFailureArgsRecursive(TypeBundle<RestOfExpected...>(),
91+
TypeBundle<RestOfActual...>());
92+
}
93+
94+
public:
95+
/// Validate that it's okay to construct a Failure with the given arguments.
96+
template <class KindTy, class... ArgTys>
97+
static void validateFailureArgs(KindTy ty, ArgTys &&... argTys) {
98+
using ExpectedArgTypes = typename ArgTypesForFailureKind<KindTy>::types;
99+
validateFailureArgsRecursive(ExpectedArgTypes(), TypeBundle<ArgTys...>());
100+
}
101+
102+
private:
103+
static const char *getTextForKind(Kind kind) {
104+
switch (kind) {
105+
#define FAILURE(KIND, TEXT, ARGTYS) \
106+
case Kind::KIND: return TEXT;
107+
#include "swift/Remote/FailureKinds.def"
108+
}
109+
}
110+
111+
union ArgStorage {
112+
std::string String;
113+
RemoteAddress Address;
114+
115+
ArgStorage() {}
116+
ArgStorage(const ArgStorage &other) = delete;
117+
ArgStorage &operator=(const ArgStorage &other) = delete;
118+
~ArgStorage() {}
119+
};
120+
enum class ArgStorageKind : char {
121+
None,
122+
String, // std::string
123+
Address, // RemoteAddress
124+
};
125+
126+
enum {
127+
MaxArgs = 4
128+
};
129+
130+
Kind TheKind;
131+
ArgStorageKind ArgKinds[MaxArgs];
132+
ArgStorage Args[MaxArgs];
133+
134+
template <unsigned Index>
135+
void initArgs() {
136+
static_assert(Index <= MaxArgs, "index out of bounds");
137+
for (unsigned i = Index; i < MaxArgs; ++i) {
138+
ArgKinds[i] = ArgStorageKind::None;
139+
}
140+
}
141+
142+
template <unsigned Index, class T, class... Ts>
143+
void initArgs(T &&nextArg, Ts &&... restOfArgs) {
144+
static_assert(Index < MaxArgs, "index out of bounds");
145+
initArg(Index, std::forward<T>(nextArg));
146+
initArgs<Index + 1>(std::forward<T>(restOfArgs)...);
147+
}
148+
149+
void initArg(unsigned index, std::string &&string) {
150+
ArgKinds[index] = ArgStorageKind::String;
151+
new (&Args[index]) std::string(std::move(string));
152+
}
153+
154+
void initArg(unsigned index, const std::string &string) {
155+
ArgKinds[index] = ArgStorageKind::String;
156+
new (&Args[index]) std::string(string);
157+
}
158+
159+
void initArg(unsigned index, RemoteAddress address) {
160+
ArgKinds[index] = ArgStorageKind::Address;
161+
new (&Args[index]) RemoteAddress(address);
162+
}
163+
164+
public:
165+
template <class KindTy, class... Ts>
166+
explicit Failure(KindTy kind, Ts &&...args) : TheKind(Kind(kind)) {
167+
validateFailureArgs(kind, std::forward<Ts>(args)...);
168+
initArgs<0>(std::forward<Ts>(args)...);
169+
}
170+
171+
Failure(const Failure &other) : TheKind(other.TheKind) {
172+
for (unsigned i = 0; i != MaxArgs; ++i) {
173+
ArgKinds[i] = other.ArgKinds[i];
174+
switch (ArgKinds[i]) {
175+
case ArgStorageKind::None:
176+
break;
177+
case ArgStorageKind::String:
178+
::new (&Args[i].String) std::string(other.Args[i].String);
179+
break;
180+
case ArgStorageKind::Address:
181+
::new (&Args[i].Address) RemoteAddress(other.Args[i].Address);
182+
break;
183+
}
184+
}
185+
}
186+
187+
Failure(Failure &&other) : TheKind(other.TheKind) {
188+
for (unsigned i = 0; i != MaxArgs; ++i) {
189+
ArgKinds[i] = other.ArgKinds[i];
190+
switch (ArgKinds[i]) {
191+
case ArgStorageKind::None:
192+
break;
193+
case ArgStorageKind::String:
194+
::new (&Args[i].String) std::string(std::move(other.Args[i].String));
195+
break;
196+
case ArgStorageKind::Address:
197+
::new (&Args[i].Address) RemoteAddress(std::move(other.Args[i].Address));
198+
break;
199+
}
200+
}
201+
}
202+
203+
Failure &operator=(const Failure &other) {
204+
this->~Failure();
205+
::new (this) Failure(other);
206+
return *this;
207+
}
208+
209+
Failure &operator=(Failure &&other) {
210+
this->~Failure();
211+
::new (this) Failure(std::move(other));
212+
return *this;
213+
}
214+
215+
~Failure() {
216+
for (unsigned i = 0; i != MaxArgs; ++i) {
217+
switch (ArgKinds[i]) {
218+
case ArgStorageKind::None:
219+
break;
220+
case ArgStorageKind::String:
221+
Args[i].String.~basic_string();
222+
break;
223+
case ArgStorageKind::Address:
224+
Args[i].Address.~RemoteAddress();
225+
break;
226+
}
227+
}
228+
}
229+
230+
/// Return the kind of failure.
231+
Kind getKind() const { return TheKind; }
232+
233+
/// Return the number of arguments to the failure.
234+
unsigned getNumArgs() const {
235+
unsigned i = 0;
236+
for (; i != MaxArgs; ++i) {
237+
// Stop at the first missing argument.
238+
if (ArgKinds[i] == ArgStorageKind::None)
239+
break;
240+
}
241+
return i;
242+
}
243+
244+
/// Render the failure as an error message.
245+
std::string render() const {
246+
std::string result;
247+
248+
const char *text = getTextForKind(TheKind);
249+
while (const char *next = std::strchr(text, '%')) {
250+
// Append everything we just skipped over.
251+
result.append(text, next - text);
252+
253+
// Skip the '%'.
254+
next++;
255+
256+
// Do something based on the character after '%'.
257+
char c = *next++;
258+
if (c == '%') {
259+
result += c;
260+
continue;
261+
}
262+
263+
assert('0' <= c && c <= '9');
264+
unsigned argIndex = c - '0';
265+
assert(argIndex < MaxArgs);
266+
267+
switch (ArgKinds[argIndex]) {
268+
case ArgStorageKind::None:
269+
LLVM_BUILTIN_UNREACHABLE;
270+
271+
// Stringize a string argument by just appending it.
272+
case ArgStorageKind::String:
273+
result += Args[argIndex].String;
274+
continue;
275+
276+
// Stringize an address argument as a hex number. We assume that an
277+
// address less than 2^32 is for a 32-bit target and accordingly
278+
// only print 8 digits for it.
279+
//
280+
// It is really silly to provide our own hex-stringization here,
281+
// but swift::remote is supposed to be a minimal, header-only library.
282+
case ArgStorageKind::Address: {
283+
result += '0';
284+
result += 'x';
285+
uint64_t address = Args[argIndex].Address.getAddressData();
286+
unsigned max = ((address >> 32) != 0 ? 16 : 8);
287+
for (unsigned i = 0; i != max; ++i) {
288+
result += "0123456789abcdef"[(address >> (max - 1 - i) * 4) & 0xF];
289+
}
290+
continue;
291+
}
292+
}
293+
LLVM_BUILTIN_UNREACHABLE;
294+
}
295+
296+
// Append the rest of the string.
297+
result.append(text);
298+
299+
return result;
300+
}
301+
};
302+
303+
template <class... Tys>
304+
struct Failure::TypeBundleForFunctionTypeParameters<void(Tys...)> {
305+
using types = TypeBundle<Tys...>;
306+
};
307+
308+
template <class... Tys> class TypeBundle {};
309+
310+
#define FAILURE(KIND, TEXT, ARGTYS) \
311+
template <> struct Failure::ArgTypesForFailureKind<Failure::KIND##_t> { \
312+
using String = ArgType_String; \
313+
using Address = ArgType_Address; \
314+
using types = TypeBundleForFunctionTypeParameters<void ARGTYS>::types; \
315+
};
316+
#include "swift/Remote/FailureKinds.def"
317+
318+
template <>
319+
struct Failure::IsAcceptableArgType<Failure::ArgType_String, const char *> {
320+
static constexpr bool value = true;
321+
};
322+
323+
template <>
324+
struct Failure::IsAcceptableArgType<Failure::ArgType_String, std::string> {
325+
static constexpr bool value = true;
326+
};
327+
328+
template <>
329+
struct Failure::IsAcceptableArgType<Failure::ArgType_Address, RemoteAddress> {
330+
static constexpr bool value = true;
331+
};
332+
333+
} // end namespace remote
334+
} // end namespace swift
335+
336+
#endif // SWIFT_REMOTE_FAILURE_H
337+

include/swift/Remote/FailureKinds.def

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===--- FailureKinds.def - Remote failure definitions ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// FAILURE(KIND, TEXT, ARGTYS)
14+
15+
FAILURE(Unknown, "an unknown failure occurred", ())
16+
FAILURE(Memory, "an unknown failure occurred while reading %0 at address %1",
17+
(String, Address))
18+
19+
#undef FAILURE

include/swift/Remote/MemoryReader.h

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,13 @@
1818
#ifndef SWIFT_REMOTE_MEMORYREADER_H
1919
#define SWIFT_REMOTE_MEMORYREADER_H
2020

21-
#include <cstdint>
21+
#include "swift/Remote/RemoteAddress.h"
22+
2223
#include <string>
2324

2425
namespace swift {
2526
namespace remote {
2627

27-
/// An abstract address in the remote process's address space.
28-
class RemoteAddress {
29-
uint64_t Data;
30-
public:
31-
explicit RemoteAddress(const void *localPtr)
32-
: Data(reinterpret_cast<uintptr_t>(localPtr)) {}
33-
34-
explicit RemoteAddress(uint64_t addressData) : Data(addressData) {}
35-
36-
explicit operator bool() const {
37-
return Data != 0;
38-
}
39-
40-
template <class T>
41-
const T *getLocalPointer() const {
42-
return reinterpret_cast<const T*>(static_cast<uintptr_t>(Data));
43-
}
44-
45-
uint64_t getAddressData() const {
46-
return Data;
47-
}
48-
};
49-
5028
/// An abstract interface for reading memory.
5129
///
5230
/// This abstraction presents memory as if it were a read-only

0 commit comments

Comments
 (0)