lldb should warn when dSYM does not match the binary.

o Symbols.cpp:

  Emit a warning message when dSYM does not match the binary.

o warnings/uuid:

  Added regression test case.

o lldbtest.py:

  Modified to allow test case writer to demand that the build command does not begin
  with a clean first; required to make TestUUIDMismatchWanring.py work.

rdar://problem/10515708

llvm-svn: 149465
This commit is contained in:
Johnny Chen 2012-02-01 01:49:50 +00:00
parent 05e8d19446
commit fdc80a5cf7
8 changed files with 197 additions and 28 deletions

View File

@ -24,6 +24,7 @@
#include "lldb/Core/Timer.h"
#include "lldb/Core/UUID.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Utility/CleanUp.h"
#include "Host/macosx/cfcpp/CFCBundle.h"
#include "Host/macosx/cfcpp/CFCReleaser.h"
@ -116,7 +117,18 @@ SkinnyMachOFileContainsArchAndUUID
if (cmd == LoadCommandUUID)
{
lldb_private::UUID file_uuid (data.GetData(&data_offset, 16), 16);
return file_uuid == *uuid;
if (file_uuid == *uuid)
return true;
// Emit some warning messages since the UUIDs do not match!
char path_buf[PATH_MAX];
path_buf[0] = '\0';
const char *path = file_spec.GetPath(path_buf, PATH_MAX) ? path_buf
: file_spec.GetFilename().AsCString();
Host::SystemLog (Host::eSystemLogWarning,
"warning: UUID mismatch detected between binary and:\n\t'%s'\n",
path);
return false;
}
data_offset = cmd_offset + cmd_size;
}

View File

@ -854,28 +854,28 @@ class Base(unittest2.TestCase):
# Build methods supported through a plugin interface
# ==================================================
def buildDefault(self, architecture=None, compiler=None, dictionary=None):
def buildDefault(self, architecture=None, compiler=None, dictionary=None, clean=True):
"""Platform specific way to build the default binaries."""
if lldb.skip_build_and_cleanup:
return
module = builder_module()
if not module.buildDefault(self, architecture, compiler, dictionary):
if not module.buildDefault(self, architecture, compiler, dictionary, clean):
raise Exception("Don't know how to build default binary")
def buildDsym(self, architecture=None, compiler=None, dictionary=None):
def buildDsym(self, architecture=None, compiler=None, dictionary=None, clean=True):
"""Platform specific way to build binaries with dsym info."""
if lldb.skip_build_and_cleanup:
return
module = builder_module()
if not module.buildDsym(self, architecture, compiler, dictionary):
if not module.buildDsym(self, architecture, compiler, dictionary, clean):
raise Exception("Don't know how to build binary with dsym")
def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
def buildDwarf(self, architecture=None, compiler=None, dictionary=None, clean=True):
"""Platform specific way to build binaries with dwarf maps."""
if lldb.skip_build_and_cleanup:
return
module = builder_module()
if not module.buildDwarf(self, architecture, compiler, dictionary):
if not module.buildDwarf(self, architecture, compiler, dictionary, clean):
raise Exception("Don't know how to build binary with dwarf")
def cleanup(self, dictionary=None):

View File

@ -63,25 +63,38 @@ def getCmdLine(d):
return " " + cmdline
def buildDefault(sender=None, architecture=None, compiler=None, dictionary=None):
def buildDefault(sender=None, architecture=None, compiler=None, dictionary=None, clean=True):
"""Build the binaries the default way."""
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary) + "; make"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
if clean:
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary) + "; make"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
else:
lldbtest.system(["/bin/sh", "-c",
"make" + getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building default.
return True
def buildDwarf(sender=None, architecture=None, compiler=None, dictionary=None):
def buildDwarf(sender=None, architecture=None, compiler=None, dictionary=None, clean=True):
"""Build the binaries with dwarf debug info."""
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary)
+ "; make MAKE_DSYM=NO"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
if clean:
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary)
+ "; make MAKE_DSYM=NO"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
else:
lldbtest.system(["/bin/sh", "-c",
"make MAKE_DSYM=NO"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building dwarf.
return True

View File

@ -5,14 +5,21 @@ from builder_base import *
#print "Hello, darwin plugin!"
def buildDsym(sender=None, architecture=None, compiler=None, dictionary=None):
def buildDsym(sender=None, architecture=None, compiler=None, dictionary=None, clean=True):
"""Build the binaries with dsym debug info."""
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary)
+ "; make MAKE_DSYM=YES"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
if clean:
lldbtest.system(["/bin/sh", "-c",
"make clean" + getCmdLine(dictionary)
+ "; make MAKE_DSYM=YES"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
else:
lldbtest.system(["/bin/sh", "-c",
"make MAKE_DSYM=YES"
+ getArchSpec(architecture) + getCCSpec(compiler)
+ getCmdLine(dictionary)],
sender=sender)
# True signifies that we can handle building dsym.
return True

View File

@ -1,4 +1,4 @@
from builder_base import *
def buildDsym(sender=None, architecture=None, compiler=None, dictionary=None):
def buildDsym(sender=None, architecture=None, compiler=None, dictionary=None, clean=True):
return False

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,113 @@
"""Test that the 'warning: UUID mismatch detected ...' message is emitted."""
import os, time
import unittest2
import lldb
import pexpect
from lldbtest import *
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
class UUIDMismatchWarningCase(TestBase):
mydir = os.path.join("warnings", "uuid")
@classmethod
def classCleanup(cls):
"""Cleanup the test byproducts."""
system(["/bin/sh", "-c", "rm -f child_send.txt"])
system(["/bin/sh", "-c", "rm -f child_read.txt"])
def setUp(self):
TestBase.setUp(self)
self.template = 'main.cpp.template'
self.source = 'main.cpp'
self.teardown_hook_added = False
def test_uuid_mismatch_warning(self):
"""Test that the 'warning: UUID mismatch detected ...' message is emitted."""
# Call the program generator to produce main.cpp, version 1.
self.generate_main_cpp(version=1)
self.line_to_break = line_number(self.source, '// Set breakpoint here.')
self.buildDsym(clean=True)
# Insert some delay and then call the program generator to produce main.cpp, version 2.
time.sleep(5)
self.generate_main_cpp(version=101)
# Now call make again, but this time don't generate the dSYM.
self.buildDwarf(clean=False)
self.exe_name = 'a.out'
self.check_executable_and_dsym(self.exe_name)
def generate_main_cpp(self, version=0):
"""Generate main.cpp from main.cpp.template."""
temp = os.path.join(os.getcwd(), self.template)
with open(temp, 'r') as f:
content = f.read()
new_content = content.replace('%ADD_EXTRA_CODE%',
'printf("This is version %d\\n");' % version)
src = os.path.join(os.getcwd(), self.source)
with open(src, 'w') as f:
f.write(new_content)
# The main.cpp has been generated, add a teardown hook to remove it.
if not self.teardown_hook_added:
self.addTearDownHook(lambda: os.remove(src))
self.teardown_hook_added = True
def check_executable_and_dsym(self, exe_name):
"""Sanity check executable compiled from the auto-generated program."""
# The default lldb prompt.
prompt = "(lldb) "
# So that the child gets torn down after the test.
self.child = pexpect.spawn('%s %s' % (self.lldbHere, self.lldbOption))
child = self.child
# Turn on logging for input/output to/from the child.
with open('child_send.txt', 'w') as f_send:
with open('child_read.txt', 'w') as f_read:
child.logfile_send = f_send
child.logfile_read = f_read
child.expect_exact(prompt)
child.setecho(True)
# Execute the file command, followed by a breakpoint set, the
# UUID mismatch warning should be generated by then.
child.sendline("file %s" % exe_name)
child.expect_exact(prompt)
child.sendline("breakpoint set -f %s -l %d" % (self.source, self.line_to_break))
child.expect_exact(prompt)
child.sendline("run")
child.expect_exact(prompt)
# Now that the necessary logging is done, restore logfile to None to
# stop further logging.
child.logfile_send = None
child.logfile_read = None
with open('child_send.txt', 'r') as fs:
if self.TraceOn():
print "\n\nContents of child_send.txt:"
print fs.read()
with open('child_read.txt', 'r') as fr:
from_child = fr.read()
if self.TraceOn():
print "\n\nContents of child_read.txt:"
print from_child
# Test that str_input completes to our patterns.
# If each pattern matches from_child, the completion mechanism works!
self.expect(from_child, msg="UUID mismatch expected!", exe=False,
substrs = ['warning: UUID mismatch detected'])
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,19 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
int
main(int argc, char const *argv[])
{
int my_int = argc + 3;
printf("Hello UUID Mismatch: %d\n", my_int); // Set breakpoint here.
%ADD_EXTRA_CODE%
return 0;
}