[upload_debug_symbols] Verify .debug_info section

For each .debug file, check whether .debug_info section
exists. If not, log a warning and skip.

Bug: IN-1666
Change-Id: I8988c1cde514998c9e1121d64c39db969ae6edef
diff --git a/cmd/upload_debug_symbols/main.go b/cmd/upload_debug_symbols/main.go
index 7120e68..0d350c7 100644
--- a/cmd/upload_debug_symbols/main.go
+++ b/cmd/upload_debug_symbols/main.go
@@ -80,6 +80,7 @@
 	if err != nil {
 		return fmt.Errorf("failed to collect symbol files: %v", err)
 	}
+	bfrs = filterEmptyDebugSymbolFiles(bfrs)
 	jobs, err := queueJobs(bfrs)
 	if err != nil {
 		return fmt.Errorf("failed to queue jobs: %v", err)
@@ -98,6 +99,22 @@
 	return nil
 }
 
+// Returns filtered input of BinaryFileRefs, skipping files without .debug_info header.
+func filterEmptyDebugSymbolFiles(bfrs []elflib.BinaryFileRef) []elflib.BinaryFileRef {
+	var filteredBfrs []elflib.BinaryFileRef
+	for _, bfr := range bfrs {
+		hasDebugInfo, err := bfr.HasDebugInfo()
+		if err != nil {
+			log.Printf("WARNING: cannot read file %s: %v, skipping\n", bfr.Filepath, err)
+		} else if !hasDebugInfo {
+			log.Printf("WARNING: file %s missing .debug_info section, skipping\n", bfr.Filepath)
+		} else {
+			filteredBfrs = append(filteredBfrs, bfr)
+		}
+	}
+	return filteredBfrs
+}
+
 // Creates BinaryFileRefs for all debug symbol files in the directories named in dirs.
 func collectDebugSymbolFiles(dirs []string) ([]elflib.BinaryFileRef, error) {
 	var out []elflib.BinaryFileRef
diff --git a/elflib/elflib.go b/elflib/elflib.go
index 7d5cc25..d01273d 100644
--- a/elflib/elflib.go
+++ b/elflib/elflib.go
@@ -70,6 +70,21 @@
 	return newBuildIDError(fmt.Errorf("build ID `%s` could not be found", b.BuildID), b.Filepath)
 }
 
+// Check if file contains debug_info section.
+func (b BinaryFileRef) HasDebugInfo() (bool, error) {
+	elfFile, err := elf.Open(b.Filepath)
+	if err != nil {
+		return false, err
+	}
+	defer elfFile.Close()
+	for _, section := range elfFile.Sections {
+		if section != nil && section.Name == ".debug_info" {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
 // rounds 'x' up to the next 'to' aligned value
 func alignTo(x, to uint32) uint32 {
 	return (x + to - 1) & -to