Commit Graph

2525 Commits

Author SHA1 Message Date
Enrico Granata ba4b8b0917 Add a language objc class-table dump command
This command dumps a bunch of interesting facts about all Objective-C classes known to LLDB in the inferior process

llvm-svn: 236640
2015-05-06 21:01:07 +00:00
Pavel Labath ad5ee04058 Simplify FuncUnwinders::GetEHFrameAugmentedUnwindPlan
Summary:
GetEHFrameAugmentedUnwindPlan duplicated the work of GetEHFrameUnwindPlan in getting the original
plan from DWARF CFI. This changes the function to call GetEHFrameUnwindPlan instead of doing all
the work itself. A copy constructor is added to UnwindPlan to enable plan copying.

Test Plan: No regressions on linux test suite.

Reviewers: jasonmolenda, clayborg

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D9369

llvm-svn: 236607
2015-05-06 15:54:48 +00:00
Colin Riley c9c55a26bd Add language command and LanguageRuntime plugin changes to allow vending of command objects.
Differential Revision: http://reviews.llvm.org/D9402

llvm-svn: 236443
2015-05-04 18:39:38 +00:00
Chaoren Lin ec53482aef PosixPipes should not be copyable but should be movable.
Summary: This addresses Oleksiy's comment in D9307.

Reviewers: clayborg, ovyalov

Reviewed By: clayborg, ovyalov

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D9405

llvm-svn: 236320
2015-05-01 16:49:23 +00:00
Sean Callanan 80c9759ef7 Added support for locating and importing functions
(including inline functions) from modules in the
expression parser.  We now have to retain a reference
to the code generator in ClangExpressionDeclMap so
that any imported function bodies can be appropriately
sent to that code generator.

<rdar://problem/19883002>

llvm-svn: 236297
2015-05-01 00:47:29 +00:00
Zachary Turner 26c0a5ea0d Remove the NullLog class introduced in r236174.
Based on list discussions, a different approach is desired for
reducing the visual impact of logging statements on the
readability of the code.  Another mechanism will be added in
a followup patch, but for now, since NullLog is unreferenced,
this patch just removes it.

This patch does *not* remove the other half of r236174, which was
to delete some dead code surrounding logging flags.

llvm-svn: 236259
2015-04-30 21:03:37 +00:00
Zachary Turner c1592658d5 Introduce a NullLog class, which ignores all messages.
The purpose of this class is so that GetLogIfAllCategoriesSet
can always return an instance of some class, whether it be a real
logging class or a "null" class, which ignores messages.  Code
that is littered with if statements that only log if the pointer
is non-null can get very unwieldy very quickly, so this should
help code readability in such circumstances.

Since I'm in this code anyway, I'm also deleting the
PrintfWithFlags methods, as well as all the flags, since they
appear to be dead code that have been superceded by newer
mechanisms and all the flags are simply ignored.

llvm-svn: 236174
2015-04-29 22:55:28 +00:00
Chaoren Lin 66f2e12f7a Expose Close{Read/Write}FileDescriptor for pipes.
llvm-svn: 236136
2015-04-29 18:25:18 +00:00
Chaoren Lin a52f48412d Add file descriptor constructor for PipePosix.
llvm-svn: 236133
2015-04-29 17:36:58 +00:00
Chaoren Lin 3eb4b4589e Remove trap code from disassembly.
Summary:
NativeProcessProtocol uses ReadMemory internally for setting/checking
breakpoints but also for generic memory reads (Handle_m), this change adds a
ReadMemoryWithoutTrap for that purpose. Also fixes a bunch of misuses of addr_t
as size/length.

Test Plan: `disassemble` no longer shows the trap code.

Reviewers: jingham, vharron, clayborg

Reviewed By: clayborg

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D9330

llvm-svn: 236132
2015-04-29 17:24:48 +00:00
Ilia K 7f83624222 Add language option in -gdb-show command (MI)
Summary:
Add language option in -gdb-show command + test:
```
$ bin/lldb-mi ~/p/hello
[...]
b main
[...]
r
[...]
(gdb)
-gdb-show language
^done,value="c++"
(gdb)
quit
```

Test Plan: ./dotest.py -v --executable $BUILDDIR/bin/lldb tools/lldb-mi/

Reviewers: abidh, granata.enrico, jingham, clayborg

Reviewed By: clayborg

Subscribers: lldb-commits, jingham, granata.enrico, clayborg, abidh

Differential Revision: http://reviews.llvm.org/D9279

llvm-svn: 235983
2015-04-28 12:51:16 +00:00
Chaoren Lin 368c9f6e9b Add an unnamed pipe fail-safe to launching lldb-gdbserver.
Summary:
Currently, launching lldb-gdbserver from platform on Android requires root for
mkfifo() and an explicit TMPDIR variable. This should remove both requirements.

Test Plan: Successfully launched lldb-gdbserver on a non-rooted Android device.

Reviewers: tberghammer, vharron, clayborg

Reviewed By: clayborg

Subscribers: tberghammer, lldb-commits

Differential Revision: http://reviews.llvm.org/D9307

llvm-svn: 235940
2015-04-27 23:20:30 +00:00
Ilia K ce216063ac Add SBLaunchInfo in include/lldb/API/SBDefines.h and fix spacing in scripts/Python/buildSwigPython.py
llvm-svn: 235819
2015-04-26 07:51:14 +00:00
Adrian McCarthy 2304b6ff44 Factor resolution of abbreviations and aliases so that they can be tested directly. http://reviews.llvm.org/D9033
llvm-svn: 235633
2015-04-23 20:00:25 +00:00
Mohit K. Bhakkad e8659b5df6 [LLDB][MIPS] Add MIPS32 and MIPS64 core revisions
Patch by Jaydeep Patil

Added MIPS32 and MIPS64 core revisions. This would be followed by register context and emulate-instruction for MIPS32.

DYLDRendezvous.cpp:
On Linux link map struct does not contain extra load offset field.

Reviewers: clayborg
Subscribers: bhushan, mohit.bhakkad, sagar, lldb-commits.
Differential Revision: http://reviews.llvm.org/D9190

llvm-svn: 235574
2015-04-23 06:36:20 +00:00
Jim Ingham a72b31c79e This is some groundwork for filtering the language Exception
breakpoints, for instance on the class of the thrown object.

This change doesn't actually make that work, the part where we
extract the thrown object type from the throw site isn't done yet.

This provides a general programmatic "precondition" that you can add
to breakpoints to give them the ability to do filtering on the LLDB
side before we pass the stop on to the user-provided conditions & 
callbacks.

llvm-svn: 235538
2015-04-22 19:42:18 +00:00
Sean Callanan f0c5aeb690 This patch implements several improvements to the
module-loading support for the expression parser.

- It adds support for auto-loading modules referred
  to by a compile unit.  These references are
  currently in the form of empty translation units.
  This functionality is gated by the setting

  target.auto-import-clang-modules (boolean) = false

- It improves and corrects support for loading
  macros from modules, currently by textually
  pasting all #defines into the user's expression.
  The improvements center around including only those
  modules that are relevant to the current context -
  hand-loaded modules and the modules that are imported
  from the current compile unit.

- It adds an "opt-in" mechanism for all of this
  functionality.  Modules have to be explicitly
  imported (via @import) or auto-loaded (by enabling
  the above setting) to enable any of this
  functionality.

It also adds support to the compile unit and symbol
file code to deal with empty translation units that
indicate module imports, and plumbs this through to
the CompileUnit interface.

Finally, it makes the following changes to the test
suite:

- It adds a testcase that verifies that modules are
  automatically loaded when the appropriate setting
  is enabled (lang/objc/modules-auto-import); and

- It modifies lanb/objc/modules-incomplete to test
  the case where a module #undefs something that is
  #defined in another module.

<rdar://problem/20299554>

llvm-svn: 235313
2015-04-20 16:31:29 +00:00
Jason Molenda ede3193bbd Add a "force_kill" arg to Process::Destroy(). This is needed after
the changes in r233255/r233258.  Normally if lldb attaches to
a running process, when we call Process::Destroy, we want to detach
from the process.  If lldb launched the process itself, ::Destroy
should kill it.

However, if we attach to a process and the driver calls SBProcess::Kill()
(which calls Destroy), we need to kill it even if we didn't launch it
originally.

The force_kill param allows for the SBProcess::Kill method to force the
behavior of Destroy.

<rdar://problem/20424439> 

llvm-svn: 235158
2015-04-17 05:01:58 +00:00
Enrico Granata 66eda7323c Fix a bug where argdumper would not launch inferiors correctly in the presence of arguments of the form word1\ word2 (vs. the quoted form "word1 word2")
Fixes rdar://20493444

llvm-svn: 235157
2015-04-17 01:50:11 +00:00
Jim Ingham de50d36ab3 Fix "help language", the languages printer was assuming the
eLanguageType numbers would be sequential, but vendor types
are not and the printer went crazy.

llvm-svn: 235153
2015-04-17 00:44:36 +00:00
Greg Clayton 35ca64b127 Add new virtual method for language runtime plug-ins:
virtual void
LanguageRuntime::ModulesDidLoad (const ModuleList &module_list);

Then reorganized how the objective C plug-in is notified so it will work for all LanguageRuntime subclasses.

llvm-svn: 235118
2015-04-16 17:13:34 +00:00
Sean Callanan 26760a80fc Added some documentation for ForEachMacro.
llvm-svn: 234923
2015-04-14 18:50:05 +00:00
Sean Callanan b8bf6efa6e Added support to ClangUserExpression for importing
all the macros from the modules the user has loaded.
These macros are currently imported textually into
the expression's source code, which turns out not to
impose the horrific string processing overhead that
I thought it would, but I still plan to look into
performance improvements.

Also modified TestCModules to test that this works.

llvm-svn: 234922
2015-04-14 18:36:17 +00:00
Siva Chandra 0f404e0575 [IRForTarget] Strenghten handling of alternate mangling.
Summary:
This fixes an issue with GCC generated binaries wherein an expression
with method invocations on std::string variables was failing. Such use
cases are tested in TestSTL (albeit, in a test marked with
@unittest2.expectedFailure because of other reasons).

The reason for this particular failure with GCC is that the generated
DWARF for std::basic_string<...> is incomplete, which makes clang not
to use the alternate mangling scheme. GCC correctly generates the name
of basic_string<...>:

DW_AT_name "basic_string<char, std::char_traits<char>, std::allocator<char> >"

It also lists the template parameters of basic_string correctly:

DW_TAG_template_type_parameter
    DW_AT_name                  "_CharT"
    DW_AT_type                  <0x0000009c>
DW_TAG_template_type_parameter
    DW_AT_name                  "_Traits"
    DW_AT_type                  <0x00000609>
DW_TAG_template_type_parameter
    DW_AT_name                  "_Alloc"
    DW_AT_type                  <0x000007fb>

However, it does not list the template parameters of std::char_traits<>.
This makes Clang feel (while parsing the expression) that the string
variable is not actually a basic_string instance, and consequently does
not use the alternate mangling scheme.

Test Plan:
dotest.py -C gcc -p TestSTL
          -- See it go past the "for" loop expression successfully.

Reviewers: clayborg, spyffe

Reviewed By: clayborg, spyffe

Subscribers: tberghammer, zturner, lldb-commits

Differential Revision: http://reviews.llvm.org/D8846

llvm-svn: 234522
2015-04-09 18:48:34 +00:00
Ilia K 1355c047ab Fix Debugger::HandleProcessEvent in case when ProcessIOHandler doesn't exist
Summary:
Previously the Debugger::HandleProcessEvent hid a top IOHandler if the
process's IOHandler was inactive and later refreshed it. Usually the
IOHandler.Refresh() prints the (lldb) prompt. The problem was in case of
iOS remote platform when trying to execute 'command source' command.
On this platform the process's IOHandler is empty, therefore the
Debugger::HandleProcessEvent hid a top IOHandler and later refreshed it.
So that the (lldb) prompt was printed with a program output in mixed
order:
was:
```
  longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
  longlonglonglonglonglonglonglonglonglonglonglonglonglonglon(lldb)
  glonglonglonglonglonglonglonglonglonglonglonglong string
```

now:
```
  longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
  longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
  longlonglonglonglonglonglonglonglong string
```

Reviewers: zturner, jingham, clayborg

Reviewed By: clayborg

Subscribers: lldb-commits, jingham, zturner, clayborg

Differential Revision: http://reviews.llvm.org/D8929

llvm-svn: 234517
2015-04-09 18:18:10 +00:00
Zachary Turner 4e8ddf5333 [Python] Fix issue configuring sys.path during startup.
Previously, users on Windows had to manually specify PYTHONPATH
to point to the site-packages directory before running LLDB.
The reason for this was because sys.path was being initialized
with a path containing unescaped backslashes, causing escape
sequences to end up in the paths.

llvm-svn: 234516
2015-04-09 18:08:50 +00:00
Stephane Sezer 9901e9c6c8 Fix resolution of certain recursive types.
Summary:
If a struct type S has a member T that has a member that is a function that
returns a typedef of S* the respective field would be duplicated, which caused
an assert down the line in RecordLayoutBuilder. This patch adds a check that
removes the possibility of trying to resolve the same type twice within the
same callstack.

This commit also adds unit tests for these failures.

Fixes https://llvm.org/bugs/show_bug.cgi?id=20486.

Patch by Cristian Hancila.

Test Plan: Run unit tests.

Reviewers: clayborg spyffe

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D8561

llvm-svn: 234441
2015-04-08 21:52:45 +00:00
David Blaikie bcd891f417 Remove redundant virtual for member functions marked 'override'.
llvm-svn: 234422
2015-04-08 17:22:09 +00:00
Greg Clayton ab745c2ad8 Fix stepping a virtual thread when the python operating system was enabled.
The OperatingSystem plug-ins allow code to detect threads in memory and then say "memory thread 0x11111" is backed by the actual thread 1. 

You can then single step these virtual threads. A problem arose when thread specific breakpoints were used during thread plans where we would say "set a breakpoint on thread 0x11111" and we would hit the breakpoint on the real thread 1 and the thread IDs wouldn't match and we would get rid of the "stopped at breakpoint" stop info due to this mismatch. Code was added to ensure these events get forwarded and thus allow single stepping a memory thread to work correctly.

Added a test case for this as well.

<rdar://problem/19211770>

llvm-svn: 234364
2015-04-07 22:17:41 +00:00
Tamas Berghammer c85b580e98 Fix host config for Android and remove android specific part form Linux.
llvm-svn: 234322
2015-04-07 16:08:32 +00:00
Sean Callanan 8505434011 Added a testcase that covers loading a module and
verifying that the types from that module don't
override types from DWARF.  Also added a target setting
to LLDB so we can tell Clang where to look for these
local modules.

<rdar://problem/18805055>

llvm-svn: 234016
2015-04-03 15:39:47 +00:00
Colin Riley 9e14f61f51 Adding the RenderScript language type.
Differential Revision: http://reviews.llvm.org/D8803

llvm-svn: 234002
2015-04-03 09:03:15 +00:00
Zachary Turner 48b475cbaa Fix warnings generated by clang-cl.
There were a couple of real bugs here regarding error checking and
signed/unsigned comparisons, but mostly these were just noise.

There was one class of bugs fixed here which is particularly
annoying, dealing with MSVC's non-standard behavior regarding
the underlying type of enums.  See the comment in
lldb-enumerations.h for details.  In short, from now on please use
FLAGS_ENUM and FLAGS_ANONYMOUS_ENUM when defining enums which
contain values larger than can fit into a signed integer.

llvm-svn: 233943
2015-04-02 20:57:38 +00:00
Greg Clayton c00ca313fd Fix a crasher that could happen when you run LLDB and evaluate an expression where the objective C runtime registers a helper function, and also have an Objective C or C++ exception breakpoint. When shutting down the process in Process::Finalize() we clear a STL collection class and that causes objects to be destroyed that could re-enter Process and cause it to try to iterate over that same collection class that is being destroyed.
Guard against this by setting a new "m_finalizing" flag that lets us know we are in the process of finalizing.

<rdar://problem/20369152>

llvm-svn: 233935
2015-04-02 18:44:58 +00:00
Siva Chandra 2af5dbb1dd Remove the unused m_ast_context member of ClangExpressionParser.
Test Plan: Build LLDB.

Reviewers: spyffe

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D8791

llvm-svn: 233868
2015-04-02 00:02:46 +00:00
Zachary Turner e6e2bb3842 Rework LLDB system initialization.
In an effort to reduce binary size for components not wishing to
link against all of LLDB, as well as a parallel effort to reduce
link dependencies on Python, this patch splits out the notion of
LLDB initialization into "full" and "common" initialization.

All code related to initializing the full LLDB suite lives directly
in API now.  Previously it was only referenced from API, but because
it was defined in lldbCore, it would get implicitly linked against
by everything including lldb-server, causing a considerable
increase in binary size.

By moving this to the API layer, it also creates a better layering
for the ongoing effort to make the embedded interpreter replacable
with one from a different language (or even be completely removeable).

One semantic change necessary to get this all working was to remove
the notion of a shared debugger refcount.  The debugger is either
initialized or uninitialized now, and calling Initialize() multiple
times will simply have no effect, while the first Terminate() will
now shut it down no matter how many times Initialize() was called.
This behaves nicely with all of our supported usage patterns though,
and allows us to fix a number of nasty hacks from before.

Differential Revision: http://reviews.llvm.org/D8462

llvm-svn: 233758
2015-03-31 21:03:22 +00:00
Greg Clayton 902716728c Make sure that "add-dsym" can't crash us when using it.
I am fixing this by:
1 - make sure we aren't trying to set the symbol file for a module to the same thing it already has and leaving it alone if it is the same
2 - keep all old symbol files around in the module in case there are any outstanding type references

<rdar://problem/18029116>

llvm-svn: 233757
2015-03-31 21:01:48 +00:00
Tamas Berghammer dccbfaf917 Fix type detection for 'char' variables
A char can have signed and unsigned encoding but previously lldb always
assumed it is signed. This CL adds a logic to detect the encoding of
'char' types based on the default encoding on the target architecture.
It fixes variable printing and expression evaluation on architectures
where 'char' is signed by default.

Differential revision: http://reviews.llvm.org/D8636

llvm-svn: 233682
2015-03-31 10:21:50 +00:00
Vince Harron 33aea9001a Increate backlog of lldb-platform's listener socket
lldb-platform's listener socket only had a backlog of one connection.
That means that if more than one client connected simultaneously, the
connection would be refused. The test suite can be run remotely with
dozens of threads connecting simultaneously. Raised this limit to 100
to effectively eliminate lost connections.

Test Plan:
run tests against a remote target

Differential Revision: http://reviews.llvm.org/D8696

llvm-svn: 233652
2015-03-31 00:27:10 +00:00
Oleksiy Vyalov 6f001068d3 Use Android device serial number instead of hostname as a target identifier within module cache.
http://reviews.llvm.org/D8597

llvm-svn: 233202
2015-03-25 17:58:13 +00:00
Tamas Berghammer d542efde8b Remove virtual and add override for lots of function.
Effeted pathes:
* Host/posix/*
* Platform/gdb-server/*
* Process/Linux/*
* Process/POSIX/*

llvm-svn: 233193
2015-03-25 15:37:56 +00:00
Robert Flack a0e70cd4b6 Allow multiple simultaneous connections to platform.
Adds the --server argument to lldb-server platform which when specified will allow multiple simultaneous connections by forking off to handle each individual connection. This will allow us to run the remote tests in parallel.

Test Plan:
Run: lldb-server platform --listen *:1234 --server
Connect from multiple lldb clients simultaneously.
I will also test running the test suite remotely with multiple simultaneous jobs.

Differential Revision: http://reviews.llvm.org/D8452

llvm-svn: 233185
2015-03-25 12:51:31 +00:00
Oleksiy Vyalov 037f6b9c0f Fix ModuleCache usage in Platform - ask remote platform for module's ModuleSpec beforehand so we can look for a module by UUID locally without need to download it.
http://reviews.llvm.org/D8557

llvm-svn: 233136
2015-03-24 23:45:49 +00:00
Chaoren Lin f9e915ae10 ComputeSupportExeDirectory for Linux
Summary:
Fixes http://reviews.llvm.org/D8511

The original method of using dladdr() could return the incorrect relative
path if not dynamically linked against liblldb and the working directory
has changed. This is not a problem when built with python, since
ScriptInterpreterPython::InitializePrivate calls
HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, ...) and caches the
correct path before any changes to the working directory.

The /proc/self/exe approach fails if run using Python, but works for all other
cases (including for android, which doesn't have dladdr()).

So if we combine the two, we should reasonably cover all corner cases.

Reviewers: vharron, ovyalov, clayborg

Reviewed By: ovyalov, clayborg

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D8570

llvm-svn: 233129
2015-03-24 23:07:02 +00:00
David Blaikie 377dc25333 Fix some -Winconsistent-missing-override warnings (& some particularly weird indenting)
llvm-svn: 233123
2015-03-24 22:10:47 +00:00
Zachary Turner a98fac28aa Fix error introduced by changing function signatures.
Since ClangASTSource::layoutRecordType() was overriding a virtual
function in the base, this was inadvertently causing a new method
to be introduced rather than an override.  To fix this all method
signatures are changed back to taking DenseMaps, and the `override`
keyword is added to make sure this type of error doesn't happen
again.

To keep the original fix intact, which is that fields and bases
must be added in offset order, the ImportOffsetMap() function
now copies the DenseMap into a vector and then sorts the vector
on the value type (e.g. the offset) before iterating over the
sorted vector and inserting the items.

llvm-svn: 233099
2015-03-24 18:56:08 +00:00
Siva Chandra 0783ab9a7f [DWARF] If linkages names are missing, use decl context to get qualified names.
Summary:
This commit adds this alternate route only when parsing variable dies
corresponding to global or static variables. The motivation for this is that GCC
does not emit linkage names for functions and variables declared/defined in
anonymous namespaces. Having this alternate route fixes one part of
TestNamespace which fails when the test case is compiled with GCC.

An alternate route to get fully qualified names of functions whose linkage names
are missing will be added with a followup change. With that, the other failing
part of TestNamespace will also be fixed.

Test Plan: dotest.py -C gcc -p TestNamespace

Reviewers: clayborg

Reviewed By: clayborg

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D8569

llvm-svn: 233098
2015-03-24 18:32:27 +00:00
Zachary Turner 504f38da4e Fix record layout when synthesizing class types.
Prior to this patch, we would try to synthesize class types by
iterating over a DenseMap of FieldDecls and adding each one to
a CXXRecordDecl.  Since a DenseMap doesn't provide a deterministic
ordering of the elements, this would not add the fields in
FieldOffset order, but rather in some random order determined by
the memory layout of the DenseMap.

This patch fixes the issue by changing DenseMaps to vectors.  The
ability to lookup a value in the DenseMap was hardly being used,
and where it is sufficient to do a vector lookup.

Differential Revision: http://reviews.llvm.org/D8512

llvm-svn: 233090
2015-03-24 16:24:50 +00:00
Tamas Berghammer 7cb18bf537 Fetch module specification from remote process also
Previously the remote module sepcification was fetched only from the
remote platform. With this CL if we have a remote process then we ask it
if it have any information from a given module. It is required because
on android the dynamic linker only reports the name of the SO file and
the platform can't always find it without a full path (the process can
do it based on /proc/<pid>/maps).

Differential revision: http://reviews.llvm.org/D8547

llvm-svn: 233061
2015-03-24 11:15:23 +00:00
Ilia K acf28bea84 Turn off 'quit' confirmation in lldb-mi
Summary:
# Turn off interpreter.prompt-on-quit on startup (MI)
# Add CommandInterpreter::SetPromptOnQuit
# Add SBCommandInterpreter::GetPromptOnQuit/SetPromptOnQuit

All tests pass on OS X.

Test Plan:
```
-file-exec-and-symbols ~/p/hello
-break-insert -f main
-exec-run
-interpreter-exec console quit
```

Reviewers: abidh, clayborg

Reviewed By: abidh, clayborg

Subscribers: lldb-commits, clayborg, abidh

Differential Revision: http://reviews.llvm.org/D8444

llvm-svn: 233034
2015-03-23 22:45:13 +00:00