mirror of
git://git.openembedded.org/meta-openembedded
synced 2026-01-04 16:10:10 +00:00
When we search for the git repository associated with a file and the there's no repository associated, we incorrectly find the yocto repository itself. To prevent the search from finding an incorrect repository, we only accept repositories found within the build directory. Signed-off-by: Daniel Markus <daniel.markus@leica-geosystems.com> Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
232 lines
8.4 KiB
Plaintext
232 lines
8.4 KiB
Plaintext
# Inherit this class when you want to allow Mozilla Socorro to link Breakpad's
|
|
# stack trace information to the correct source code revision.
|
|
# This class creates a new version of the symbol file (.sym) created by
|
|
# Breakpad. The absolute file paths in the symbol file will be replaced by VCS,
|
|
# branch, file and revision of the source file. That information facilitates the
|
|
# lookup of a particular source code line in the stack trace.
|
|
#
|
|
# Use example:
|
|
#
|
|
# BREAKPAD_BIN = "YourBinary"
|
|
# inherit socorro-syms
|
|
#
|
|
|
|
# We depend on Breakpad creating the original symbol file.
|
|
inherit breakpad
|
|
|
|
PACKAGE_PREPROCESS_FUNCS += "symbol_file_preprocess"
|
|
PACKAGES =+ "${PN}-socorro-syms"
|
|
FILES_${PN}-socorro-syms = "/usr/share/socorro-syms"
|
|
|
|
|
|
python symbol_file_preprocess() {
|
|
|
|
package_dir = d.getVar("PKGD", True)
|
|
breakpad_bin = d.getVar("BREAKPAD_BIN", True)
|
|
if not breakpad_bin:
|
|
package_name = d.getVar("PN", True)
|
|
bb.error("Package %s depends on Breakpad via socorro-syms. See "
|
|
"breakpad.bbclass for instructions on setting up the Breakpad "
|
|
"configuration." % package_name)
|
|
raise ValueError("BREAKPAD_BIN not defined in %s." % package_name)
|
|
|
|
sym_file_name = breakpad_bin + ".sym"
|
|
|
|
breakpad_syms_dir = os.path.join(
|
|
package_dir, "usr", "share", "breakpad-syms")
|
|
socorro_syms_dir = os.path.join(
|
|
package_dir, "usr", "share", "socorro-syms")
|
|
if not os.path.exists(socorro_syms_dir):
|
|
os.makedirs(socorro_syms_dir)
|
|
|
|
breakpad_sym_file_path = os.path.join(breakpad_syms_dir, sym_file_name)
|
|
socorro_sym_file_path = os.path.join(socorro_syms_dir, sym_file_name)
|
|
|
|
create_socorro_sym_file(d, breakpad_sym_file_path, socorro_sym_file_path)
|
|
|
|
arrange_socorro_sym_file(socorro_sym_file_path, socorro_syms_dir)
|
|
|
|
return
|
|
}
|
|
|
|
|
|
def run_command(command, directory):
|
|
|
|
(output, error) = bb.process.run(command, cwd=directory)
|
|
if error:
|
|
raise bb.process.ExecutionError(command, error)
|
|
|
|
return output.rstrip()
|
|
|
|
|
|
def create_socorro_sym_file(d, breakpad_sym_file_path, socorro_sym_file_path):
|
|
|
|
# In the symbol file, all source files are referenced like the following.
|
|
# FILE 123 /path/to/some/File.cpp
|
|
# Go through all references and replace the file paths with repository
|
|
# paths.
|
|
with open(breakpad_sym_file_path, 'r') as breakpad_sym_file, \
|
|
open(socorro_sym_file_path, 'w') as socorro_sym_file:
|
|
|
|
for line in breakpad_sym_file:
|
|
if line.startswith("FILE "):
|
|
socorro_sym_file.write(socorro_file_reference(d, line))
|
|
else:
|
|
socorro_sym_file.write(line)
|
|
|
|
return
|
|
|
|
|
|
def socorro_file_reference(d, line):
|
|
|
|
# The 3rd position is the file path. See example above.
|
|
source_file_path = line.split()[2]
|
|
source_file_repo_path = repository_path(
|
|
d, os.path.normpath(source_file_path))
|
|
|
|
# If the file could be found in any repository then replace it with the
|
|
# repository's path.
|
|
if source_file_repo_path:
|
|
return line.replace(source_file_path, source_file_repo_path)
|
|
|
|
return line
|
|
|
|
|
|
def repository_path(d, source_file_path):
|
|
|
|
if not os.path.isfile(source_file_path):
|
|
return None
|
|
|
|
# Check which VCS is used and use that to extract repository information.
|
|
(output, error) = bb.process.run("git status",
|
|
cwd=os.path.dirname(source_file_path))
|
|
if not error:
|
|
# Make sure the git repository we just found wasn't the yocto repository
|
|
# itself, i.e. the root of the repository we're looking for must be a
|
|
# child of the build directory TOPDIR.
|
|
git_root_dir = run_command(
|
|
"git rev-parse --show-toplevel", os.path.dirname(source_file_path))
|
|
if not git_root_dir.startswith(d.getVar("TOPDIR", True)):
|
|
return None
|
|
|
|
return git_repository_path(source_file_path)
|
|
|
|
# Here we can add support for other VCSs like hg, svn, cvs, etc.
|
|
|
|
# The source file isn't under any VCS so we leave it be.
|
|
return None
|
|
|
|
|
|
def is_local_url(url):
|
|
|
|
return \
|
|
url.startswith("file:") or url.startswith("/") or url.startswith("./")
|
|
|
|
|
|
def git_repository_path(source_file_path):
|
|
|
|
import re
|
|
|
|
# We need to extract the following.
|
|
# (1): VCS URL, (2): branch, (3): repo root directory name, (4): repo file,
|
|
# (5): revision.
|
|
|
|
source_file_dir = os.path.dirname(source_file_path)
|
|
|
|
# (1) Get the VCS URL and extract the server part, i.e. change the URL from
|
|
# gitolite@git.someserver.com:SomeRepo.git to just git.someserver.com.
|
|
source_long_url = run_command(
|
|
"git config --get remote.origin.url", source_file_dir)
|
|
|
|
# The URL could be a local download directory. If so, get the URL again
|
|
# using the local directory's config file.
|
|
if is_local_url(source_long_url):
|
|
git_config_file = os.path.join(source_long_url, "config")
|
|
source_long_url = run_command(
|
|
"git config --file %s --get remote.origin.url" % git_config_file,
|
|
source_file_dir)
|
|
|
|
# If also the download directory redirects to a local git directory,
|
|
# then we're probably using source code from a local debug branch which
|
|
# won't be accessible by Socorro.
|
|
if is_local_url(source_long_url):
|
|
return None
|
|
|
|
# The URL can have several formats. A full list can be found using
|
|
# git help clone. Extract the server part with a regex.
|
|
url_match = re.search(".*(://|@)([^:/]*).*", source_long_url)
|
|
source_server = url_match.group(2)
|
|
|
|
# (2) Get the branch for this file.
|
|
source_branch_list = run_command("git show-branch --list", source_file_dir)
|
|
source_branch_match = re.search(".*?\[(.*?)\].*", source_branch_list)
|
|
source_branch = source_branch_match.group(1)
|
|
|
|
# (3) Since the repo root directory name can be changed without affecting
|
|
# git, we need to extract the name from something more reliable.
|
|
# The git URL has a repo name that we could use. We just need to strip off
|
|
# everything around it - from gitolite@git.someserver.com:SomeRepo.git/ to
|
|
# SomeRepo.
|
|
source_repo_dir = re.sub("/$", "", source_long_url)
|
|
source_repo_dir = re.sub("\.git$", "", source_repo_dir)
|
|
source_repo_dir = re.sub(".*[:/]", "", source_repo_dir)
|
|
|
|
# (4) We know the file but want to remove all of the build system dependent
|
|
# path up to and including the repository's root directory, e.g. remove
|
|
# /home/someuser/dev/repo/projectx/
|
|
source_toplevel = run_command(
|
|
"git rev-parse --show-toplevel", source_file_dir)
|
|
source_toplevel = source_toplevel + os.path.sep
|
|
source_file = source_file_path.replace(source_toplevel, "")
|
|
|
|
# (5) Get the source revision this file is part of.
|
|
source_revision = run_command("git rev-parse HEAD", source_file_dir)
|
|
|
|
# Assemble the repository path according to the Socorro format.
|
|
socorro_reference = "git:%s/%s:%s/%s:%s" % \
|
|
(source_server, source_branch,
|
|
source_repo_dir, source_file,
|
|
source_revision)
|
|
|
|
return socorro_reference
|
|
|
|
|
|
def arrange_socorro_sym_file(socorro_sym_file_path, socorro_syms_dir):
|
|
|
|
import re
|
|
|
|
# Breakpad's minidump_stackwalk needs a certain directory structure in order
|
|
# to find correct symbols when extracting a stack trace out of a minidump.
|
|
# The directory structure must look like the following.
|
|
# YourBinary/<hash>/YourBinary.sym
|
|
# YourLibrary.so/<hash>/YourLibrary.so.sym
|
|
# To be able to create such structure we need to extract the hash value that
|
|
# is found in each symbol file. The header of the symbol file looks
|
|
# something like this:
|
|
# MODULE Linux x86 A079E473106CE51C74C1C25AF536CCD30 YourBinary
|
|
# See
|
|
# http://code.google.com/p/google-breakpad/wiki/LinuxStarterGuide
|
|
|
|
# Create the directory with the same name as the binary.
|
|
binary_dir = re.sub("\.sym$", "", socorro_sym_file_path)
|
|
if not os.path.exists(binary_dir):
|
|
os.makedirs(binary_dir)
|
|
|
|
# Get the hash from the header of the symbol file.
|
|
with open(socorro_sym_file_path, 'r') as socorro_sym_file:
|
|
|
|
# The hash is the 4th argument of the first line.
|
|
sym_file_hash = socorro_sym_file.readline().split()[3]
|
|
|
|
# Create the hash directory.
|
|
hash_dir = os.path.join(binary_dir, sym_file_hash)
|
|
if not os.path.exists(hash_dir):
|
|
os.makedirs(hash_dir)
|
|
|
|
# Move the symbol file to the hash directory.
|
|
sym_file_name = os.path.basename(socorro_sym_file_path)
|
|
os.rename(socorro_sym_file_path, os.path.join(hash_dir, sym_file_name))
|
|
|
|
return
|
|
|