Merge lp:~achiang/ubuntu-nexus7/valgrind-ubuntu-dbg-packages into lp:~ubuntu-nexus7/ubuntu-nexus7/valgrind-ubuntu-dbg-packages

Proposed by Alex Chiang on 2012-11-19
Status: Work in progress
Proposed branch: lp:~achiang/ubuntu-nexus7/valgrind-ubuntu-dbg-packages
Merge into: lp:~ubuntu-nexus7/ubuntu-nexus7/valgrind-ubuntu-dbg-packages
Diff against target: 166 lines (+157/-0)
2 files modified
valgrind-ubuntu-dbg-packages.go (+92/-0)
valgrind-ubuntu-dbg-packages.py (+65/-0)
To merge this branch: bzr merge lp:~achiang/ubuntu-nexus7/valgrind-ubuntu-dbg-packages
Reviewer Review Type Date Requested Status
Mike Carifio (community) Abstain on 2012-11-20
Dimitri John Ledkov (community) Needs Fixing on 2012-11-20
Scott Sweeny (community) 2012-11-19 Approve on 2012-11-20
Martin Pitt 2012-11-20 Pending
Review via email: mp+134841@code.launchpad.net

Description of the Change

  Parallel python and go implementations of valgrind-ubuntu-dbg-packages

  These tools parse a valgrind log looking for unknown symbols. It then
  attempts to find a corresponding Ubuntu package that might provide the
  proper debug symbols, and finally recommends them for installation by
  the user.

  Usage:
    <script> <valgrind.log>

  To build the go version:
    go build valgrind-ubuntu-dbg-packages.go

To post a comment you must log in.
3. By Alex Chiang on 2012-11-19

Re-implement in functional style

I found the multiple "found = True" statements to be a bit ugly so
refactored into a functional implementation.

At the bottom, you see that I compare the package sets returned by
the two implementations, and the output on the console is:

set([])

Therefore, I claim the functional implementation is equivalent to the
iterative implementation.

4. By Alex Chiang on 2012-11-19

Remove iterative implementation of find_pkgs()

The previous commit proved they were equivalent, so now let's get rid
of the old one.

5. By Alex Chiang on 2012-11-19

Fix debug print statements

- Remove superfluous prints that existed to print empty lines
- When no debug package found, print full name of original package

Alex Chiang (achiang) wrote :

To understand the purpose of this helper program, you can run it on the log attached to comment #52 of a recent bug I worked on:

https://bugs.launchpad.net/ubuntu/+source/network-manager-applet/+bug/780602/comments/52

Scott Sweeny (ssweeny) wrote :

Python script looks reasonable, and pylint/pep8 only show nitpicks, so I approve.

I'm not really qualified to review Go code, but the output of the Go program is functionally equivalent to the python script, so I feel good about it too :)

review: Approve
Dimitri John Ledkov (xnox) wrote :

Reviewing the python bits only.
Might be easier to use python-apt and/or python-debian bindings.
The code is not python3-safe.

General:
Only small subset of packages have -dbg packages. Most debug packages are generated as ddebs and are have -dbgsym suffix. https://wiki.ubuntu.com/DebuggingProgramCrash#Debug_Symbol_Packages

We already have daisy and apport re-tracers that can find missing debug packages, can we not adapt/use those?

review: Needs Fixing
Martin Pitt (pitti) wrote :

It depends on how far you want to go with those. Installing -dbg packages only is insufficient for a lot of cases (as many/most packages don't build them), but is "safe" in the sense that they will always stay installable and upgradeable. Using -dbgsym isn't, due to the hackish and convoluted way that we (have to) use to build the ddebs archive. I would _not_ recommend to permanently install those.

Instead, what I recommend is to install apport-retrace and if you have a crash, use it to debug a .crash file in a temporary sandbox (-S system) which will include all available dbgsyms, not only for the transitive dependencies of a package, but also from the dynamically loaded plugins of the program.

What's the purpose of the script, i. e. in which cases would you run this? Is that an use case which should be supported by apport-retrace?

Alex Chiang (achiang) wrote :

The goal of this script was not to help debug crashers, but rather with the aim of providing a convenience script for community members as the Ubuntu Nexus 7 memory slimming program gets under way.

The idea was that as people run valgrind on individual programs, they might want to install the -dbg packages relevant to the program they are tracing. They might valgrind a program once, briefly; capture the log; then run this convenience script on the log.

The tool tells them which extra -dbg packages are available, user installs them, and then user re-runs valgrind for real.

Martin Pitt (pitti) wrote :

Right, so for permanent installation I indeed recommend installing -dbg only, not ddebs. For the "full" symbol experience the ddebs should be installed only temporarily (they are not very stable on upgrades and also take a ton of space), so something similar like apport-retrace ("apport-valgrind package" or so) would be more appropriate, if the need arises.

Mike Carifio (carifio) wrote :

As per our recent discussion in #premium, the golang portion is fine idomatic go. I didn't test it however.

If you want convert the go implementation to do the equivalent of python generators (the functions with yield in them), then I suggest golang channels and "go routines", see http://jnwhiteh.net/posts/2010/09/go-examples-1-channels-and-goroutines.html for a quick tutorial-by-example.

review: Abstain
Alex Chiang (achiang) wrote :

Hi Martin,

Thanks for the feedback, but I'm a little confused. Are you suggesting to fold this work into apport instead?

Hi Dmitrijs,

Based on Martin's feedback, I'll either fix the python up to be python3 compliant or figure out how to make it work with apport.

Martin Pitt (pitti) wrote :

> Thanks for the feedback, but I'm a little confused. Are you suggesting to fold
> this work into apport instead?

I was saying "if the need arises". If you prefer having permanently installed debug packages, and the number of -dbg that we have are sufficient for what you are trying to do, it's fine.

Unmerged revisions

5. By Alex Chiang on 2012-11-19

Fix debug print statements

- Remove superfluous prints that existed to print empty lines
- When no debug package found, print full name of original package

4. By Alex Chiang on 2012-11-19

Remove iterative implementation of find_pkgs()

The previous commit proved they were equivalent, so now let's get rid
of the old one.

3. By Alex Chiang on 2012-11-19

Re-implement in functional style

I found the multiple "found = True" statements to be a bit ugly so
refactored into a functional implementation.

At the bottom, you see that I compare the package sets returned by
the two implementations, and the output on the console is:

set([])

Therefore, I claim the functional implementation is equivalent to the
iterative implementation.

2. By Alex Chiang on 2012-11-19

Parallel python and go implementations of valgrind-ubuntu-dbg-packages

These tools parse a valgrind log looking for unknown symbols. It then
attempts to find a corresponding Ubuntu package that might provide the
proper debug symbols, and finally recommends them for installation by
the user.

Usage:
  <script> <valgrind.log>

To build the go version:
  go build valgrind-ubuntu-dbg-packages.go

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'valgrind-ubuntu-dbg-packages.go'
2--- valgrind-ubuntu-dbg-packages.go 1970-01-01 00:00:00 +0000
3+++ valgrind-ubuntu-dbg-packages.go 2012-11-19 16:50:28 +0000
4@@ -0,0 +1,92 @@
5+package main
6+
7+import (
8+ "fmt"
9+ "os"
10+ "io"
11+ "flag"
12+ "bufio"
13+ "strings"
14+ "path/filepath"
15+ "os/exec"
16+)
17+
18+func find_syms(log *os.File) map[string]string {
19+ syms := make(map[string]string)
20+
21+ f := bufio.NewReader(log)
22+ for {
23+ line, err := f.ReadString('\n')
24+ if err == io.EOF {
25+ break
26+ }
27+
28+ if strings.Contains(line, "??? (in") {
29+ fields := strings.Split(line, " ")
30+ path := strings.TrimRight(fields[8], ")\n")
31+ base := filepath.Base(path)
32+ if _, ok := syms[base]; !ok {
33+ syms[base] = path
34+ }
35+ }
36+ }
37+ return syms
38+}
39+
40+func find_pkgs(syms map[string]string) map[string]bool {
41+ pkgs := make(map[string]bool)
42+
43+ for k, v := range syms {
44+ out, _:= exec.Command("dpkg-query", "-S", v).Output()
45+ dbg := ""
46+ found := false
47+
48+ deb_package := strings.Split(string(out), ":")
49+ pkg_parts := strings.Split(deb_package[0], "-")
50+
51+ fmt.Println("File", k, "provided by", deb_package[0])
52+
53+ for i := range pkg_parts {
54+ dbg += pkg_parts[i]
55+ fmt.Println("Searching for", dbg + "-dbg")
56+ out, _ := exec.Command("apt-cache", "search", dbg + "-dbg").Output()
57+ if string(out) != "" {
58+ pkg := strings.Split(strings.TrimRight(string(out), "\n"), " ")[0]
59+ if _, ok := pkgs[pkg]; ok {
60+ fmt.Println("Already found", pkg)
61+ found = true
62+ break
63+ }
64+ pkgs[pkg] = true
65+ fmt.Println("Found", pkg)
66+ found = true
67+ break
68+ }
69+ dbg += "-"
70+ }
71+ dbg = ""
72+ if found == false {
73+ fmt.Println("No debug package for", k)
74+ }
75+ fmt.Println()
76+ }
77+ return pkgs
78+}
79+
80+func main() {
81+ flag.Parse()
82+
83+ log, err := os.Open(flag.Arg(0))
84+ if err != nil {
85+ fmt.Println("Error:", err)
86+ os.Exit(1)
87+ }
88+
89+ syms := find_syms(log)
90+ pkgs := find_pkgs(syms)
91+ fmt.Println("It is recommended to install the following packages:")
92+ for k := range pkgs {
93+ fmt.Printf("%s ", k)
94+ }
95+ fmt.Println()
96+}
97
98=== added file 'valgrind-ubuntu-dbg-packages.py'
99--- valgrind-ubuntu-dbg-packages.py 1970-01-01 00:00:00 +0000
100+++ valgrind-ubuntu-dbg-packages.py 2012-11-19 16:50:28 +0000
101@@ -0,0 +1,65 @@
102+#!/usr/bin/python
103+
104+import sys
105+import re
106+import os
107+
108+def find_syms(log):
109+ syms = {}
110+
111+ f = open(log)
112+ for l in f.readlines():
113+ if re.search('\?\?\?\ \(in', l):
114+ fields = re.split(' ', l)
115+ path = fields[8].rstrip('\)\r\n')
116+ lib = os.path.basename(path)
117+ if lib not in syms:
118+ syms[lib] = path
119+ else:
120+ continue
121+ return syms
122+
123+def find_pkgs(syms):
124+ from subprocess import Popen, PIPE
125+ def find_pkg(k, v):
126+ out = Popen(("dpkg-query -S %s" % v), stdout=PIPE, shell=True).stdout.read()
127+ deb_package = out.split(":")
128+ parts = deb_package[0].split("-")
129+ print "File %s provided by %s " % (k, deb_package[0])
130+ yield parts
131+
132+ def find_dbg(pkg_parts):
133+ dbg = ""
134+ for i in pkg_parts:
135+ dbg += i
136+ print "Searching for %s" % dbg + "-dbg"
137+ out = Popen(("apt-cache search %s" % dbg + "-dbg"), stdout=PIPE, shell=True).stdout.read()
138+ if out != "":
139+ pkg = out.rstrip("\n").split(" ")[0]
140+ print "Found %s\n" % pkg
141+ yield pkg
142+ return
143+ dbg += "-"
144+ print "No debug package for %s\n" % "-".join(pkg_parts)
145+ return
146+
147+ pkgs = dict((dbg, True)
148+ for k, v in syms.items()
149+ for pkg in find_pkg(k, v)
150+ for dbg in find_dbg(pkg))
151+
152+ return pkgs
153+
154+if __name__ == "__main__":
155+ try:
156+ log = sys.argv[1]
157+ except:
158+ print "No log file supplied"
159+ sys.exit(1)
160+
161+ syms = find_syms(log)
162+ pkgs = find_pkgs(syms)
163+ print "It is recommended to install the following packages:"
164+ for p in pkgs:
165+ print p,
166+ print

Subscribers

People subscribed via source and target branches