func NewReader(r io.Reader) *Reader { reader := &Reader{} reader.archive = C.archive_read_new() C.archive_read_support_filter_all(reader.archive) C.archive_read_support_format_all(reader.archive) reader.reader = r C.go_libarchive_set(reader.archive) C.archive_read_set_callback_data(reader.archive, unsafe.Pointer(reader)) runtime.SetFinalizer(reader, func(r *Reader) { C.archive_read_free(r.archive) }) return reader }
// Free frees the resources the underlying libarchive archive is using // calling archive_read_free func (r *Reader) Free() error { if C.archive_read_free(r.archive) == ARCHIVE_FATAL { return ErrArchiveFatal } return nil }
func process_package(packages []string, filename string) { // RPM transcation stuff ts := C.rpmtsCreate() defer C.rpmtsFree(ts) C.rpmtsSetRootDir(ts, nil) C.rpmtsSetVSFlags(ts, C._RPMVSF_NOSIGNATURES) // create a lookup table for the files in debuginfo RPM // libarchive is too slow for doing this due to lzma decoding! cmode := C.CString("r") defer C.free(unsafe.Pointer(cmode)) debug_package := filename cfilename := C.CString(debug_package) defer C.free(unsafe.Pointer(cfilename)) /* debug_files := make(map[string]bool) dfd := C.Fopen(cfilename, cmode) defer C.Fclose(dfd) var dhdr C.Header drc := C.rpmReadPackageFile(ts, dfd, cfilename, &dhdr) if drc != C.RPMRC_OK { log.Println("[-] %s, broken RPM?", filename) return } defer C.headerFree(dhdr) fi := C.rpmfiNew(ts, dhdr, C.RPMTAG_BASENAMES, C.RPMFI_FLAGS_QUERY) defer C.rpmfiFree(fi) fi = C.rpmfiInit(fi, 0) for C.rpmfiNext(fi) >= 0 { fn := C.rpmfiFN(fi) // defer C.free(unsafe.Pointer(fn)) gfn := C.GoString(fn) if strings.HasSuffix(gfn, ".debug") { debug_files[gfn] = true } } */ // get the "dwz" content for this debug_package a := C.archive_read_new() defer C.archive_read_free(a) C.archive_read_support_filter_all(a) C.archive_read_support_format_all(a) r := C.archive_read_open_filename(a, cfilename, 30240) if r != C.ARCHIVE_OK { log.Println("[-] %s, broken archive?", debug_package) } pentry := C.archive_entry_new() var dwzfile *elf.File var err error for C.archive_read_next_header(a, &pentry) == C.ARCHIVE_OK { f := C.archive_entry_pathname(pentry) entryname := C.GoString(f) size := C.archive_entry_size(pentry) // skip folders mode := C.archive_entry_mode(pentry) gmode := int(mode) if gmode&0040000 != 0 { continue } // get the "dwz" content for this debug_package if strings.Contains(entryname, "lib/debug/.dwz/") { dwzbuf := unsafe.Pointer((*C.char)(C.malloc((C.size_t)(size)))) defer C.free(unsafe.Pointer(dwzbuf)) read_length := C.archive_read_data(a, dwzbuf, C.size_t(size)) log.Println("[DWZ] read", read_length, "bytes from", entryname) // C array to Go array without explicit copying // https://code.google.com/p/go-wiki/wiki/cgo // dwzdata := (*[1<<31 - 1]byte)(unsafe.Pointer(dwzbuf))[:size] // https://code.google.com/p/go-wiki/wiki/cgo#Turning_C_arrays_into_Go_slices length := int(size) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(dwzbuf)), Len: length, Cap: length, } dwzdata := *(*[]byte)(unsafe.Pointer(&hdr)) if len(dwzdata) > 0 { dwzfile, err = elf.NewFile(bytes.NewReader(dwzdata)) if err != nil { log.Println(err) } } break } } // process ".debug" file(s) in debug_package m := make(map[string][]string) var debugfile *elf.File var e error b := C.archive_read_new() defer C.archive_read_free(b) C.archive_read_support_filter_all(b) C.archive_read_support_format_all(b) pentry = C.archive_entry_new() C.archive_read_open_filename(b, cfilename, 30240) for C.archive_read_next_header(b, &pentry) == C.ARCHIVE_OK { f := C.archive_entry_pathname(pentry) entryname := C.GoString(f) size := C.archive_entry_size(pentry) // skip folders and symlinks mode := C.archive_entry_mode(pentry) gmode := int(mode) // S_IFLNK 0120000 symbolic link // S_IFMT 0170000 bit mask for the file type bit fields // S_IFDIR 0040000 directory if gmode&0040000 != 0 || gmode&0170000 == 0120000 { continue } // skip zero sized entries if size == 0 { continue } // skip non-debug files if !strings.HasSuffix(entryname, ".debug") || strings.Contains(entryname, "debug/.build-id/") { continue } // log.Println("<+> loading", entryname) // allocate buffer for reading data cbuf := unsafe.Pointer((*C.char)(C.malloc((C.size_t)(size)))) read_length := C.archive_read_data(b, cbuf, C.size_t(size)) log.Println("[DEBUG] read", read_length, "bytes from", entryname) // data := (*[1<<31 - 1]byte)(unsafe.Pointer(cbuf))[:size] // will break at 2.14 GB! // https://code.google.com/p/go-wiki/wiki/cgo#Turning_C_arrays_into_Go_slices length := int(size) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cbuf)), Len: length, Cap: length, } data := *(*[]byte)(unsafe.Pointer(&hdr)) if len(data) > 0 { debugfile, e = elf.NewFile(bytes.NewReader(data)) if e != nil { log.Println(e, entryname, len(data)) continue } } else { log.Println(len(data), entryname, debug_package) } // log.Println("<+> loaded", entryname) // time.Sleep(1 * time.Millisecond) // real action time ;( output := producer(debugfile, dwzfile, entryname, filename) m[entryname] = output C.free(unsafe.Pointer(cbuf)) } stuff, bad := json.Marshal(m) if bad != nil { log.Panic(bad) } fmt.Println(string(stuff)) }