mirror of
https://github.com/golang/go
synced 2024-11-07 14:26:11 -07:00
cmd: add DWARF64 support for aix port
This commit adds support for DWARF 64bits which is needed for AIX operating system. It also adds the save of each compilation unit's size which will be used during XCOFF generation in a following patch. Updates: #25893 Change-Id: Icdd0a4dd02bc0a9f0df319c351fb1db944610015 Reviewed-on: https://go-review.googlesource.com/c/138729 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
bcc3447be5
commit
75a0b9dbf3
@ -179,7 +179,7 @@ type Context interface {
|
|||||||
AddBytes(s Sym, b []byte)
|
AddBytes(s Sym, b []byte)
|
||||||
AddAddress(s Sym, t interface{}, ofs int64)
|
AddAddress(s Sym, t interface{}, ofs int64)
|
||||||
AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
|
AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
|
||||||
AddDWARFSectionOffset(s Sym, size int, t interface{}, ofs int64)
|
AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64)
|
||||||
CurrentOffset(s Sym) int64
|
CurrentOffset(s Sym) int64
|
||||||
RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int)
|
RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int)
|
||||||
RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32)
|
RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32)
|
||||||
@ -895,7 +895,7 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
|
|||||||
|
|
||||||
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
|
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
|
||||||
if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges
|
if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges
|
||||||
ctxt.AddDWARFSectionOffset(s, 4, data, value)
|
ctxt.AddDWARFAddrSectionOffset(s, data, value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ctxt.AddInt(s, 4, value)
|
ctxt.AddInt(s, 4, value)
|
||||||
@ -932,7 +932,7 @@ func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, da
|
|||||||
if data == nil {
|
if data == nil {
|
||||||
return fmt.Errorf("dwarf: null reference in %d", abbrev)
|
return fmt.Errorf("dwarf: null reference in %d", abbrev)
|
||||||
}
|
}
|
||||||
ctxt.AddDWARFSectionOffset(s, 4, data, value)
|
ctxt.AddDWARFAddrSectionOffset(s, data, value)
|
||||||
|
|
||||||
case DW_FORM_ref1, // reference within the compilation unit
|
case DW_FORM_ref1, // reference within the compilation unit
|
||||||
DW_FORM_ref2, // reference
|
DW_FORM_ref2, // reference
|
||||||
|
@ -459,7 +459,12 @@ func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
|
|||||||
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
||||||
panic("should be used only in the linker")
|
panic("should be used only in the linker")
|
||||||
}
|
}
|
||||||
func (c dwCtxt) AddDWARFSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
|
||||||
|
size := 4
|
||||||
|
if isDwarf64(c.Link) {
|
||||||
|
size = 8
|
||||||
|
}
|
||||||
|
|
||||||
ls := s.(*LSym)
|
ls := s.(*LSym)
|
||||||
rsym := t.(*LSym)
|
rsym := t.(*LSym)
|
||||||
ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
|
ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
|
||||||
@ -500,6 +505,10 @@ func (c dwCtxt) Logf(format string, args ...interface{}) {
|
|||||||
c.Link.Logf(format, args...)
|
c.Link.Logf(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isDwarf64(ctxt *Link) bool {
|
||||||
|
return ctxt.Headtype == objabi.Haix
|
||||||
|
}
|
||||||
|
|
||||||
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) {
|
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfIsStmtSym *LSym) {
|
||||||
if s.Type != objabi.STEXT {
|
if s.Type != objabi.STEXT {
|
||||||
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
||||||
|
@ -67,7 +67,12 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
|
|||||||
r.Add = ofs
|
r.Add = ofs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c dwctxt) AddDWARFSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
|
||||||
|
size := 4
|
||||||
|
if isDwarf64(c.linkctxt) {
|
||||||
|
size = 8
|
||||||
|
}
|
||||||
|
|
||||||
c.AddSectionOffset(s, size, t, ofs)
|
c.AddSectionOffset(s, size, t, ofs)
|
||||||
ls := s.(*sym.Symbol)
|
ls := s.(*sym.Symbol)
|
||||||
ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF
|
ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF
|
||||||
@ -95,6 +100,10 @@ func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []
|
|||||||
panic("should be used only in the compiler")
|
panic("should be used only in the compiler")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isDwarf64(ctxt *Link) bool {
|
||||||
|
return ctxt.HeadType == objabi.Haix
|
||||||
|
}
|
||||||
|
|
||||||
var gdbscript string
|
var gdbscript string
|
||||||
|
|
||||||
var dwarfp []*sym.Symbol
|
var dwarfp []*sym.Symbol
|
||||||
@ -873,6 +882,33 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createUnitLength creates the initial length field with value v and update
|
||||||
|
// offset of unit_length if needed.
|
||||||
|
func createUnitLength(ctxt *Link, s *sym.Symbol, v uint64) {
|
||||||
|
if isDwarf64(ctxt) {
|
||||||
|
s.AddUint32(ctxt.Arch, 0xFFFFFFFF)
|
||||||
|
}
|
||||||
|
addDwarfAddrField(ctxt, s, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addDwarfAddrField adds a DWARF field in DWARF 64bits or 32bits.
|
||||||
|
func addDwarfAddrField(ctxt *Link, s *sym.Symbol, v uint64) {
|
||||||
|
if isDwarf64(ctxt) {
|
||||||
|
s.AddUint(ctxt.Arch, v)
|
||||||
|
} else {
|
||||||
|
s.AddUint32(ctxt.Arch, uint32(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addDwarfAddrRef adds a DWARF pointer in DWARF 64bits or 32bits.
|
||||||
|
func addDwarfAddrRef(ctxt *Link, s *sym.Symbol, t *sym.Symbol) {
|
||||||
|
if isDwarf64(ctxt) {
|
||||||
|
adddwarfref(ctxt, s, t, 8)
|
||||||
|
} else {
|
||||||
|
adddwarfref(ctxt, s, t, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// compilationUnit is per-compilation unit (equivalently, per-package)
|
// compilationUnit is per-compilation unit (equivalently, per-package)
|
||||||
// debug-related data.
|
// debug-related data.
|
||||||
type compilationUnit struct {
|
type compilationUnit struct {
|
||||||
@ -1081,11 +1117,11 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
|
|||||||
// Write .debug_line Line Number Program Header (sec 6.2.4)
|
// Write .debug_line Line Number Program Header (sec 6.2.4)
|
||||||
// Fields marked with (*) must be changed for 64-bit dwarf
|
// Fields marked with (*) must be changed for 64-bit dwarf
|
||||||
unitLengthOffset := ls.Size
|
unitLengthOffset := ls.Size
|
||||||
ls.AddUint32(ctxt.Arch, 0) // unit_length (*), filled in at end.
|
createUnitLength(ctxt, ls, 0) // unit_length (*), filled in at end
|
||||||
unitstart = ls.Size
|
unitstart = ls.Size
|
||||||
ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
|
ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
|
||||||
headerLengthOffset := ls.Size
|
headerLengthOffset := ls.Size
|
||||||
ls.AddUint32(ctxt.Arch, 0) // header_length (*), filled in at end.
|
addDwarfAddrField(ctxt, ls, 0) // header_length (*), filled in at end
|
||||||
headerstart = ls.Size
|
headerstart = ls.Size
|
||||||
|
|
||||||
// cpos == unitstart + 4 + 2 + 4
|
// cpos == unitstart + 4 + 2 + 4
|
||||||
@ -1238,8 +1274,16 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
|
|||||||
dwarf.Uleb128put(dwarfctxt, ls, 1)
|
dwarf.Uleb128put(dwarfctxt, ls, 1)
|
||||||
ls.AddUint8(dwarf.DW_LNE_end_sequence)
|
ls.AddUint8(dwarf.DW_LNE_end_sequence)
|
||||||
|
|
||||||
ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart))
|
if ctxt.HeadType == objabi.Haix {
|
||||||
ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart))
|
saveDwsectCUSize(".debug_line", unit.lib.String(), uint64(ls.Size-unitLengthOffset))
|
||||||
|
}
|
||||||
|
if isDwarf64(ctxt) {
|
||||||
|
ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF
|
||||||
|
ls.SetUint(ctxt.Arch, headerLengthOffset, uint64(headerend-headerstart))
|
||||||
|
} else {
|
||||||
|
ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart))
|
||||||
|
ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart))
|
||||||
|
}
|
||||||
|
|
||||||
// Apply any R_DWARFFILEREF relocations, since we now know the
|
// Apply any R_DWARFFILEREF relocations, since we now know the
|
||||||
// line table file indices for this compilation unit. Note that
|
// line table file indices for this compilation unit. Note that
|
||||||
@ -1329,8 +1373,8 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
|||||||
if haslinkregister(ctxt) {
|
if haslinkregister(ctxt) {
|
||||||
cieReserve = 32
|
cieReserve = 32
|
||||||
}
|
}
|
||||||
fs.AddUint32(ctxt.Arch, cieReserve) // initial length, must be multiple of thearch.ptrsize
|
createUnitLength(ctxt, fs, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize
|
||||||
fs.AddUint32(ctxt.Arch, 0xffffffff) // cid.
|
addDwarfAddrField(ctxt, fs, 0xffffffff) // cid.
|
||||||
fs.AddUint8(3) // dwarf version (appendix F)
|
fs.AddUint8(3) // dwarf version (appendix F)
|
||||||
fs.AddUint8(0) // augmentation ""
|
fs.AddUint8(0) // augmentation ""
|
||||||
dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor
|
dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor
|
||||||
@ -1418,9 +1462,9 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
|||||||
// ptrsize: address range
|
// ptrsize: address range
|
||||||
fs.AddUint32(ctxt.Arch, uint32(4+2*ctxt.Arch.PtrSize+len(deltaBuf))) // length (excludes itself)
|
fs.AddUint32(ctxt.Arch, uint32(4+2*ctxt.Arch.PtrSize+len(deltaBuf))) // length (excludes itself)
|
||||||
if ctxt.LinkMode == LinkExternal {
|
if ctxt.LinkMode == LinkExternal {
|
||||||
adddwarfref(ctxt, fs, fs, 4)
|
addDwarfAddrRef(ctxt, fs, fs)
|
||||||
} else {
|
} else {
|
||||||
fs.AddUint32(ctxt.Arch, 0) // CIE offset
|
addDwarfAddrField(ctxt, fs, 0) // CIE offset
|
||||||
}
|
}
|
||||||
fs.AddAddr(ctxt.Arch, s)
|
fs.AddAddr(ctxt.Arch, s)
|
||||||
fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range
|
fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range
|
||||||
@ -1455,11 +1499,11 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
|
|||||||
// Write .debug_info Compilation Unit Header (sec 7.5.1)
|
// Write .debug_info Compilation Unit Header (sec 7.5.1)
|
||||||
// Fields marked with (*) must be changed for 64-bit dwarf
|
// Fields marked with (*) must be changed for 64-bit dwarf
|
||||||
// This must match COMPUNITHEADERSIZE above.
|
// This must match COMPUNITHEADERSIZE above.
|
||||||
s.AddUint32(ctxt.Arch, 0) // unit_length (*), will be filled in later.
|
createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
|
||||||
s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F)
|
s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F)
|
||||||
|
|
||||||
// debug_abbrev_offset (*)
|
// debug_abbrev_offset (*)
|
||||||
adddwarfref(ctxt, s, abbrevsym, 4)
|
addDwarfAddrRef(ctxt, s, abbrevsym)
|
||||||
|
|
||||||
s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size
|
s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size
|
||||||
|
|
||||||
@ -1477,8 +1521,17 @@ func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit, abbrevs
|
|||||||
for _, child := range cu {
|
for _, child := range cu {
|
||||||
cusize += child.Size
|
cusize += child.Size
|
||||||
}
|
}
|
||||||
cusize -= 4 // exclude the length field.
|
// Save size for AIX symbol table.
|
||||||
s.SetUint32(ctxt.Arch, 0, uint32(cusize))
|
if ctxt.HeadType == objabi.Haix {
|
||||||
|
saveDwsectCUSize(".debug_info", getPkgFromCUSym(s), uint64(cusize))
|
||||||
|
}
|
||||||
|
if isDwarf64(ctxt) {
|
||||||
|
cusize -= 12 // exclude the length field.
|
||||||
|
s.SetUint(ctxt.Arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF
|
||||||
|
} else {
|
||||||
|
cusize -= 4 // exclude the length field.
|
||||||
|
s.SetUint32(ctxt.Arch, 0, uint32(cusize))
|
||||||
|
}
|
||||||
// Leave a breadcrumb for writepub. This does not
|
// Leave a breadcrumb for writepub. This does not
|
||||||
// appear in the DWARF output.
|
// appear in the DWARF output.
|
||||||
newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0)
|
newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0)
|
||||||
@ -1519,10 +1572,10 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s
|
|||||||
culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4
|
culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4
|
||||||
|
|
||||||
// Write .debug_pubnames/types Header (sec 6.1.1)
|
// Write .debug_pubnames/types Header (sec 6.1.1)
|
||||||
s.AddUint32(ctxt.Arch, 0) // unit_length (*), will be filled in later.
|
createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
|
||||||
s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F)
|
s.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F)
|
||||||
adddwarfref(ctxt, s, dtolsym(compunit.Sym), 4) // debug_info_offset (of the Comp unit Header)
|
addDwarfAddrRef(ctxt, s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
|
||||||
s.AddUint32(ctxt.Arch, culength) // debug_info_length
|
addDwarfAddrField(ctxt, s, uint64(culength)) // debug_info_length
|
||||||
|
|
||||||
for die := compunit.Child; die != nil; die = die.Link {
|
for die := compunit.Child; die != nil; die = die.Link {
|
||||||
if !ispub(die) {
|
if !ispub(die) {
|
||||||
@ -1533,19 +1586,31 @@ func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*s
|
|||||||
if die.Sym == nil {
|
if die.Sym == nil {
|
||||||
fmt.Println("Missing sym for ", name)
|
fmt.Println("Missing sym for ", name)
|
||||||
}
|
}
|
||||||
adddwarfref(ctxt, s, dtolsym(die.Sym), 4)
|
addDwarfAddrRef(ctxt, s, dtolsym(die.Sym))
|
||||||
Addstring(s, name)
|
Addstring(s, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.AddUint32(ctxt.Arch, 0)
|
addDwarfAddrField(ctxt, s, 0) // Null offset
|
||||||
|
|
||||||
s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
|
// On AIX, save the current size of this compilation unit.
|
||||||
|
if ctxt.HeadType == objabi.Haix {
|
||||||
|
saveDwsectCUSize(sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(s.Size-sectionstart))
|
||||||
|
}
|
||||||
|
if isDwarf64(ctxt) {
|
||||||
|
s.SetUint(ctxt.Arch, sectionstart+4, uint64(s.Size-sectionstart)-12) // exclude the length field.
|
||||||
|
} else {
|
||||||
|
s.SetUint32(ctxt.Arch, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return syms
|
return syms
|
||||||
}
|
}
|
||||||
|
|
||||||
func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
|
||||||
|
// TODO (aix): make it available
|
||||||
|
if ctxt.HeadType == objabi.Haix {
|
||||||
|
return syms
|
||||||
|
}
|
||||||
if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive {
|
if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive {
|
||||||
// gcc on Windows places .debug_gdb_scripts in the wrong location, which
|
// gcc on Windows places .debug_gdb_scripts in the wrong location, which
|
||||||
// causes the program not to run. See https://golang.org/issue/20183
|
// causes the program not to run. See https://golang.org/issue/20183
|
||||||
@ -2019,3 +2084,27 @@ func (v compilationUnitByStartPC) Less(i, j int) bool {
|
|||||||
return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value
|
return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On AIX, the symbol table needs to know where are the compilation units parts
|
||||||
|
// for a specific package in each .dw section.
|
||||||
|
// dwsectCUSize map will save the size of a compilation unit for
|
||||||
|
// the corresponding .dw section.
|
||||||
|
// This size can later be retrieved with the index "sectionName.pkgName".
|
||||||
|
var dwsectCUSize map[string]uint64
|
||||||
|
|
||||||
|
// getDwsectCUSize retrieves the corresponding package size inside the current section.
|
||||||
|
func getDwsectCUSize(sname string, pkgname string) uint64 {
|
||||||
|
return dwsectCUSize[sname+"."+pkgname]
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveDwsectCUSize(sname string, pkgname string, size uint64) {
|
||||||
|
dwsectCUSize[sname+"."+pkgname] = size
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPkgFromCUSym returns the package name for the compilation unit
|
||||||
|
// represented by s.
|
||||||
|
// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get
|
||||||
|
// the package name.
|
||||||
|
func getPkgFromCUSym(s *sym.Symbol) string {
|
||||||
|
return strings.TrimPrefix(s.Name, dwarf.InfoPrefix+".pkg.")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user