summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorMark Hatle <mark.hatle@windriver.com>2011-02-08 21:46:47 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-02-25 22:43:33 +0000
commit16102e18902e56bf76d256cebb890743a05d021b (patch)
tree19f44d4425e3fd8f8102abc6e79fad942ffd6072 /meta
parent2d87d5229771ea45ced4ebd376a2582c5bed6525 (diff)
downloadpoky-16102e18902e56bf76d256cebb890743a05d021b.tar.gz
Revise stripping and splitting of debug information
We now support two styles of debug information generation, the '.debug' style, which is the same as previously implemented. This style simply splits the debug information and makes it available in the same general directory. /bin/foo -> /bin/.debug/foo The new 'debug-file-directory' style splits the debug information and places it into the single debug-file-directory, /usr/lib/debug: /bin/foo -> /usr/lib/debug/bin/foo.debug Both also find and copy all referenced source code to a new /usr/src/debug directory. This allows the -dbg files to be used for stand-a-lone debugging on or off the target device. File stripping is now handled as a seperate operation from file splitting. This allows us to split the debug information, but also leave it in the original file -- or prevent the debug information from being split. Also enhance the comments within local.conf.sample to provide a better understanding of the control the user has over debug file generation. Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
Diffstat (limited to 'meta')
-rw-r--r--meta/classes/insane.bbclass4
-rw-r--r--meta/classes/package.bbclass231
-rw-r--r--meta/conf/bitbake.conf9
-rw-r--r--meta/conf/local.conf.sample31
4 files changed, 245 insertions, 30 deletions
diff --git a/meta/classes/insane.bbclass b/meta/classes/insane.bbclass
index 5d3ef92a2e..b376470bd7 100644
--- a/meta/classes/insane.bbclass
+++ b/meta/classes/insane.bbclass
@@ -192,8 +192,8 @@ def package_qa_check_dev(path, name,d, elf):
192 192
193 sane = True 193 sane = True
194 194
195 if not name.endswith("-dev") and path.endswith(".so") and os.path.islink(path): 195 if not name.endswith("-dev") and not name.endswith("-dbg") and path.endswith(".so") and os.path.islink(path):
196 error_msg = "non -dev package contains symlink .so: %s path '%s'" % \ 196 error_msg = "non -dev/-dbg package contains symlink .so: %s path '%s'" % \
197 (name, package_qa_clean_path(path,d)) 197 (name, package_qa_clean_path(path,d))
198 sane = package_qa_handle_error(0, error_msg, name, path, d) 198 sane = package_qa_handle_error(0, error_msg, name, path, d)
199 199
diff --git a/meta/classes/package.bbclass b/meta/classes/package.bbclass
index 02c2dd3fce..86e24bc1fa 100644
--- a/meta/classes/package.bbclass
+++ b/meta/classes/package.bbclass
@@ -165,32 +165,88 @@ python () {
165 d.setVar("PACKAGERDEPTASK", "") 165 d.setVar("PACKAGERDEPTASK", "")
166} 166}
167 167
168def runstrip(file, d): 168def splitfile(file, debugfile, debugsrcdir, d):
169 # Function to strip a single file, called from split_and_strip_files below 169 # Function to split a single file, called from split_and_strip_files below
170 # A working 'file' (one which works on the target architecture) 170 # A working 'file' (one which works on the target architecture)
171 # is necessary for this stuff to work, hence the addition to do_package[depends] 171 # is split and the split off portions go to debugfile.
172 #
173 # The debug information is then processed for src references. These
174 # references are copied to debugsrcdir, if defined.
172 175
173 import commands, stat 176 import commands, stat
174 177
178 dvar = bb.data.getVar('PKGD', d, True)
175 pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, True) 179 pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, True)
180 objcopy = bb.data.getVar("OBJCOPY", d, True)
181 debugedit = bb.data.expand("${STAGING_LIBDIR_NATIVE}/rpm/bin/debugedit", d)
182 workdir = bb.data.expand("${WORKDIR}", d)
183 sourcefile = bb.data.expand("${WORKDIR}/debugsources.list", d)
176 184
177 ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, file)) 185 # We ignore kernel modules, we don't generate debug info files.
186 if file.find("/lib/modules/") != -1 and file.endswith(".ko"):
187 return 0
178 188
179 if ret: 189 newmode = None
180 bb.error("runstrip: 'file %s' failed (forced strip)" % file) 190 if not os.access(file, os.W_OK) or os.access(file, os.R_OK):
191 origmode = os.stat(file)[stat.ST_MODE]
192 newmode = origmode | stat.S_IWRITE | stat.S_IREAD
193 os.chmod(file, newmode)
181 194
182 if "not stripped" not in result: 195 # We need to extract the debug src information here...
183 bb.debug(1, "runstrip: skip %s" % file) 196 if debugsrcdir:
184 return 0 197 os.system("%s'%s' -b '%s' -d '%s' -i -l '%s' '%s'" % (pathprefix, debugedit, workdir, debugsrcdir, sourcefile, file))
185 198
186 # If the file is in a .debug directory it was already stripped, 199 bb.mkdirhier(os.path.dirname(debugfile))
187 # don't do it again... 200
188 if os.path.dirname(file).endswith(".debug"): 201 os.system("%s'%s' --only-keep-debug '%s' '%s'" % (pathprefix, objcopy, file, debugfile))
189 bb.note("Already ran strip") 202
190 return 0 203 # Set the debuglink to have the view of the file path on the target
204 os.system("%s'%s' --add-gnu-debuglink='%s' '%s'" % (pathprefix, objcopy, debugfile, file))
191 205
206 if newmode:
207 os.chmod(file, origmode)
208
209 return 0
210
211def splitfile2(debugsrcdir, d):
212 # Function to split a single file, called from split_and_strip_files below
213 #
214 # The debug src information processed in the splitfile2 is further procecessed
215 # and copied to the destination here.
216
217 import commands, stat
218
219 dvar = bb.data.getVar('PKGD', d, True)
220 pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, True)
192 strip = bb.data.getVar("STRIP", d, True) 221 strip = bb.data.getVar("STRIP", d, True)
193 objcopy = bb.data.getVar("OBJCOPY", d, True) 222 objcopy = bb.data.getVar("OBJCOPY", d, True)
223 debugedit = bb.data.expand("${STAGING_LIBDIR_NATIVE}/rpm/bin/debugedit", d)
224 workdir = bb.data.expand("${WORKDIR}", d)
225 sourcefile = bb.data.expand("${WORKDIR}/debugsources.list", d)
226
227 if debugsrcdir:
228 bb.mkdirhier(debugsrcdir)
229
230 processdebugsrc = "LC_ALL=C ; sort -z -u '%s' | egrep -v -z '(<internal>|<built-in>)$' | "
231 processdebugsrc += "(cd '%s' ; cpio -pd0mL '%s%s' 2>/dev/null)"
232
233 os.system(processdebugsrc % (sourcefile, workdir, dvar, debugsrcdir))
234
235 # The copy by cpio may have resulted in some empty directories! Remove these
236 for root, dirs, files in os.walk("%s%s" % (dvar, debugsrcdir)):
237 for d in dirs:
238 dir = os.path.join(root, d)
239 #bb.note("rmdir -p %s" % dir)
240 os.system("rmdir -p %s 2>/dev/null" % dir)
241
242def runstrip(file, d):
243 # Function to strip a single file, called from split_and_strip_files below
244 # A working 'file' (one which works on the target architecture)
245
246 import commands, stat
247
248 pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, True)
249 strip = bb.data.getVar("STRIP", d, True)
194 250
195 # Handle kernel modules specifically - .debug directories here are pointless 251 # Handle kernel modules specifically - .debug directories here are pointless
196 if file.find("/lib/modules/") != -1 and file.endswith(".ko"): 252 if file.find("/lib/modules/") != -1 and file.endswith(".ko"):
@@ -202,21 +258,22 @@ def runstrip(file, d):
202 newmode = origmode | stat.S_IWRITE | stat.S_IREAD 258 newmode = origmode | stat.S_IWRITE | stat.S_IREAD
203 os.chmod(file, newmode) 259 os.chmod(file, newmode)
204 260
261 ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, file))
262
263 if ret:
264 bb.error("runstrip: 'file %s' failed" % file)
265 return 0
266
205 extraflags = "" 267 extraflags = ""
206 if ".so" in file and "shared" in result: 268 if ".so" in file and "shared" in result:
207 extraflags = "--remove-section=.comment --remove-section=.note --strip-unneeded" 269 extraflags = "--remove-section=.comment --remove-section=.note --strip-unneeded"
208 elif "shared" in result or "executable" in result: 270 elif "shared" in result or "executable" in result:
209 extraflags = "--remove-section=.comment --remove-section=.note" 271 extraflags = "--remove-section=.comment --remove-section=.note"
210 272
211 bb.mkdirhier(os.path.join(os.path.dirname(file), ".debug"))
212 debugfile=os.path.join(os.path.dirname(file), ".debug", os.path.basename(file))
213
214 stripcmd = "'%s' %s '%s'" % (strip, extraflags, file) 273 stripcmd = "'%s' %s '%s'" % (strip, extraflags, file)
215 bb.debug(1, "runstrip: %s" % stripcmd) 274 bb.debug(1, "runstrip: %s" % stripcmd)
216 275
217 os.system("%s'%s' --only-keep-debug '%s' '%s'" % (pathprefix, objcopy, file, debugfile))
218 ret = os.system("%s%s" % (pathprefix, stripcmd)) 276 ret = os.system("%s%s" % (pathprefix, stripcmd))
219 os.system("%s'%s' --add-gnu-debuglink='%s' '%s'" % (pathprefix, objcopy, debugfile, file))
220 277
221 if newmode: 278 if newmode:
222 os.chmod(file, origmode) 279 os.chmod(file, origmode)
@@ -224,7 +281,7 @@ def runstrip(file, d):
224 if ret: 281 if ret:
225 bb.error("runstrip: '%s' strip command failed" % stripcmd) 282 bb.error("runstrip: '%s' strip command failed" % stripcmd)
226 283
227 return 1 284 return 0
228 285
229# 286#
230# Package data handling routines 287# Package data handling routines
@@ -333,10 +390,24 @@ python perform_packagecopy () {
333} 390}
334 391
335python split_and_strip_files () { 392python split_and_strip_files () {
336 import stat 393 import commands, stat, errno
337 394
338 dvar = bb.data.getVar('PKGD', d, True) 395 dvar = bb.data.getVar('PKGD', d, True)
339 396
397 # We default to '.debug' style
398 if bb.data.getVar('PACKAGE_DEBUG_SPLIT_STYLE', d, True) == 'debug-file-directory':
399 # Single debug-file-directory style debug info
400 debugappend = ".debug"
401 debugdir = ""
402 debuglibdir = "/usr/lib/debug"
403 debugsrcdir = "/usr/src/debug"
404 else:
405 # Original Poky, a.k.a. ".debug", style debug info
406 debugappend = ""
407 debugdir = "/.debug"
408 debuglibdir = ""
409 debugsrcdir = "/usr/src/debug"
410
340 os.chdir(dvar) 411 os.chdir(dvar)
341 412
342 def isexec(path): 413 def isexec(path):
@@ -344,16 +415,124 @@ python split_and_strip_files () {
344 s = os.stat(path) 415 s = os.stat(path)
345 except (os.error, AttributeError): 416 except (os.error, AttributeError):
346 return 0 417 return 0
347 return (s[stat.ST_MODE] & stat.S_IEXEC) 418 return ((s[stat.ST_MODE] & stat.S_IXUSR) or (s[stat.ST_MODE] & stat.S_IXGRP) or (s[stat.ST_MODE] & stat.S_IXOTH))
419
420 # Return 0 - not elf, 1 - ELF & not stripped, 2 - ELF & stripped
421 def isELF(path):
422 pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, True)
423 ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, path))
424
425 if ret:
426 bb.error("split_and_strip_files: 'file %s' failed" % path)
427 return 0
428
429 # Not stripped
430 if "ELF" in result and "not stripped" in result:
431 return 1
432
433 # Stripped
434 if "ELF" in result:
435 return 2
436
437 return 0;
438
439 #
440 # First lets process debug splitting
441 #
442 if (bb.data.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT', d, True) != '1'):
443 file_links = {}
348 444
349 # Figure out which packages we want to process
350 if (bb.data.getVar('INHIBIT_PACKAGE_STRIP', d, True) != '1'):
351 for root, dirs, files in os.walk(dvar): 445 for root, dirs, files in os.walk(dvar):
352 for f in files: 446 for f in files:
353 file = os.path.join(root, f) 447 file = os.path.join(root, f)
354 if not os.path.islink(file) and not os.path.isdir(file) and isexec(file): 448 # Skip debug files, it must be executable, and must be a file (or link)
355 runstrip(file, d) 449 if not (debugappend != "" and file.endswith(debugappend)) and not (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])) and isexec(file) and os.path.isfile(file):
450 src = file[len(dvar):]
451 dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
452 fpath = dvar + dest
453 # Preserve symlinks in debug area...
454 if os.path.islink(file):
455 target = os.readlink(file)
456 if not os.path.isabs(target):
457 target = os.path.join(os.path.dirname(file), target)
458 if isELF(target):
459 ltarget = os.readlink(file)
460 lpath = os.path.dirname(ltarget)
461 lbase = os.path.basename(ltarget)
462 ftarget = ""
463 if lpath and lpath != ".":
464 ftarget += lpath + debugdir + "/"
465 ftarget += lbase + debugappend
466 bb.mkdirhier(os.path.dirname(fpath))
467 #bb.note("Symlink %s -> %s" % (fpath, ftarget))
468 os.symlink(ftarget, fpath)
469 continue
470
471 # If the file is elf we need to check it for hard links
472 elf_file = isELF(file)
473 if elf_file:
474 # Preserve hard links in debug area...
475 s = os.stat(file)
476 if s.st_nlink > 1:
477 file_reference = "%d_%d" % (s.st_dev, s.st_ino)
478 if file_reference not in file_links:
479 # If this is new, and already stripped we avoid recording it
480 # as we'll be unable to set the hard link later, because it
481 # won't be split/stripped...
482 if elf_file != 2:
483 file_links[file_reference] = fpath
484 else:
485 bb.mkdirhier(os.path.dirname(fpath))
486 #bb.note("Link %s -> %s" % (fpath, file_links[file_reference]))
487 os.link(file_links[file_reference], fpath)
488 continue
489
490 if elf_file == 2:
491 bb.warn("File '%s' was already stripped, this will prevent future debugging!" % (src))
492 continue
356 493
494 # Split and Strip
495 bb.mkdirhier(os.path.dirname(fpath))
496 #bb.note("Split %s -> %s" % (file, fpath))
497 splitfile(file, fpath, debugsrcdir, d)
498
499 # Process the debugsrcdir if requested...
500 splitfile2(debugsrcdir, d)
501
502 # The above may have generated dangling symlinks
503 for root, dirs, files in os.walk(dvar):
504 for f in files:
505 file = os.path.join(root, f)
506 # We ONLY strip dangling links if they're debug generated!
507 if (debugappend != "" and file.endswith(debugappend)) or (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])):
508 try:
509 s = os.stat(file)
510 except OSError, (err, strerror):
511 if err != errno.ENOENT:
512 raise
513 #bb.note("Remove dangling link %s" % file)
514 os.unlink(file)
515
516 #
517 # End of debug splitting
518 #
519
520 #
521 # Now lets go back over things and strip them
522 #
523 if (bb.data.getVar('INHIBIT_PACKAGE_STRIP', d, True) != '1'):
524 for root, dirs, files in os.walk(dvar):
525 for f in files:
526 file = os.path.join(root, f)
527 # if not a debugfile, is executable, is a file, and not a symlink
528 if not (debugappend != "" and file.endswith(debugappend)) and not (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])) and isexec(file) and os.path.isfile(file) and not os.path.islink(file):
529 elf_file = isELF(file)
530 if elf_file and elf_file != 2:
531 #bb.note("Strip %s" % file)
532 runstrip(file, d)
533 #
534 # End of strip
535 #
357} 536}
358 537
359python populate_packages () { 538python populate_packages () {
diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
index cba918e1e7..cf99a8124b 100644
--- a/meta/conf/bitbake.conf
+++ b/meta/conf/bitbake.conf
@@ -242,9 +242,14 @@ SECTION_${PN}-dev = "devel"
242ALLOW_EMPTY_${PN}-dev = "1" 242ALLOW_EMPTY_${PN}-dev = "1"
243RDEPENDS_${PN}-dev = "${PN} (= ${EXTENDPV})" 243RDEPENDS_${PN}-dev = "${PN} (= ${EXTENDPV})"
244 244
245FILES_${PN}-dbg = "${bindir}/.debug ${sbindir}/.debug ${libexecdir}/.debug ${libdir}/.debug \ 245DOTDEBUG-dbg = "${bindir}/.debug ${sbindir}/.debug ${libexecdir}/.debug ${libdir}/.debug \
246 ${base_bindir}/.debug ${base_sbindir}/.debug ${base_libdir}/.debug ${libdir}/${PN}/.debug \ 246 ${base_bindir}/.debug ${base_sbindir}/.debug ${base_libdir}/.debug ${libdir}/${PN}/.debug \
247 ${libdir}/matchbox-panel/.debug" 247 ${libdir}/matchbox-panel/.debug /usr/src/debug"
248
249DEBUGFILEDIRECTORY-dbg = "/usr/lib/debug /usr/src/debug"
250
251FILES_${PN}-dbg = "${@bb.data.getVar(['DOTDEBUG-dbg', 'DEBUGFILEDIRECTORY-dbg'][bb.data.getVar('PACKAGE_DEBUG_SPLIT_STYLE', d, 1) == 'debug-file-directory'], d, 1)}"
252
248SECTION_${PN}-dbg = "devel" 253SECTION_${PN}-dbg = "devel"
249ALLOW_EMPTY_${PN}-dbg = "1" 254ALLOW_EMPTY_${PN}-dbg = "1"
250RRECOMMENDS_${PN}-dbg = "${PN} (= ${EXTENDPV})" 255RRECOMMENDS_${PN}-dbg = "${PN} (= ${EXTENDPV})"
diff --git a/meta/conf/local.conf.sample b/meta/conf/local.conf.sample
index 65b508717f..434c6841bf 100644
--- a/meta/conf/local.conf.sample
+++ b/meta/conf/local.conf.sample
@@ -104,6 +104,37 @@ USER_CLASSES ?= "image-mklibs image-prelink"
104# <build directory>/tmp 104# <build directory>/tmp
105#TMPDIR = "${POKYBASE}/build/tmp" 105#TMPDIR = "${POKYBASE}/build/tmp"
106 106
107# The following are used to control options related to debugging.
108#
109# Uncomment this to change the optimization to make debugging easer, at the
110# possible cost of performance.
111# DEBUG_BUILD = "1"
112#
113# Uncomment this to disable the stripping of the installed binaries
114# INHIBIT_PACKAGE_STRIP = "1"
115#
116# Uncomment this to disable the split of the debug information into -dbg files
117# INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
118#
119# When splitting debug information, the following controls the results of the
120# file splitting.
121#
122# .debug (default):
123# When splitting the debug information will be placed into
124# a .debug directory in the same dirname of the binary produced:
125# /bin/foo -> /bin/.debug/foo
126#
127# debug-file-directory:
128# When splitting the debug information will be placed into
129# a central debug-file-directory, /usr/lib/debug:
130# /bin/foo -> /usr/lib/debug/bin/foo.debug
131#
132# Any source code referenced in the debug symbols will be copied
133# and made available within the /usr/src/debug directory
134#
135PACKAGE_DEBUG_SPLIT_STYLE = '.debug'
136# PACKAGE_DEBUG_SPLIT_STYLE = 'debug-file-directory'
137
107# Uncomment these to build a package such that you can use gprof to profile it. 138# Uncomment these to build a package such that you can use gprof to profile it.
108# NOTE: This will only work with 'linux' targets, not 139# NOTE: This will only work with 'linux' targets, not
109# 'linux-uclibc', as uClibc doesn't provide the necessary 140# 'linux-uclibc', as uClibc doesn't provide the necessary